<template>
  <div class="naviga-ai">
    <!-- 导航信息 -->
    <div class="headerBox" v-if="Listfile.length > 0">
      <div class="layout">
        <!-- 文件信息 -->
        <div class="headerBox_file" :slot-scope="{ filedow }">
          <div class="btnmore" @click="goBack">
            <el-button :icon="Back" circle />
          </div>

          <div class="file_box" v-if="filedow">
            <svg-icon :icon-class="selectSvgIcons(filedow)" class="fileicon"></svg-icon>
          </div>

          <div>
            <span class="file_name">
              {{ filedow && filedow.fileName ? (filedow.fileName.length > 9 ? filedow.fileName.slice(0, 9) + '...' : filedow.fileName) : '' }}
              {{ filedow.suffix ? '.' + filedow.suffix : '' }}
            </span>
          </div>
        </div>

        <!-- 按钮信息 -->
        <div class="headerBox_btn">
          <div class="btn_more">
            <el-button :icon="MoreFilled" circle />
          </div>
          <div class="btn_more">
            <el-button :icon="Star" circle />
          </div>
          <div class="btn_more">
            <el-button :icon="MessageBox" circle />
          </div>
          <div class="btn_more">
            <el-button :icon="Position" round>分享</el-button>
          </div>
          <div class="btn_more">
            <el-button :icon="Download" type="primary" round>导出</el-button>
          </div>
        </div>
      </div>
    </div>

    <!-- 输入框 -->
    <div class="box" :style="inputStyle">
      <div class="page_left" :style="{ ...headerStyle, ...Styleheader }">
        <!-- 文档预览的位置 -->
        <div class="preview" v-if="Listfile.length > 0">
          <!-- <iframe :src="onlineSrc" scrolling="auto" frameborder="0" class="iframeClass"></iframe> -->

          <!-- onlyOffice在线预览 -->
          <el-watermark :font="font" :content="watermarkTxt" class="iframeClass">
            <div class="Online" v-loading="iframeLoading">
              <!-- 文档预览的位置 -->

              <div id="placeholder" ref="pdfframe"></div>
            </div>
          </el-watermark>

          <!-- pdf预览组件 -->
          <!-- <PreviewPdf page-scale="page-fit" class="iframeClass" theme="light" :src="pdfUrl" @loaded="onLoaded" />

          <div v-if="Pdfloading" class="loading-overlay">
            <a-spin size="large" />
          </div> -->
        </div>
      </div>

      <!-- 输入框 -->
      <div class="input-bot" :style="{ width: inputBotWidth, background: activeInput == '1' ? '#cccccc4a' : '#fff' }" v-if="isChat">
        <!-- 输入框上方导航菜单 -->
        <div class="input_tab">
          <!-- <div v-for="(v, i) in tabs" :key="i" class="talk-tab" :class="{ 'activeTab': activeInput == v.id }" @click="InputTab(v.id)">
            <svg-icon :icon-class="v.icon" class="size_icon"></svg-icon>{{ v.label }}
          </div> -->

          <div class="talk-tab" :class="{ 'activeTab': activeInput == '1' }" @click="InputTab('1')">
            <svg-icon :icon-class="activeInput == '1' ? 'ai_essay' : 'ai_essays'" class="size_icon"></svg-icon>问答
          </div>

          <div class="talk-tab" :class="{ 'activeTab': activeInput == '2' }" @click="InputTab('2')">
            <svg-icon :icon-class="activeInput == '2' ? 'ai_summary' : 'ai_summarys'" class="size_icon"></svg-icon>总结
          </div>

          <!-- <div class="talk-tab" :class="{ 'activeTab': activeInput == '3' }" @click="InputTab('3')">
            <svg-icon icon-class="ai_translate" class="size_icon"></svg-icon>翻译
          </div> -->

          <div class="talk-tab" :class="{ 'activeTab': activeInput == '4' }" @click="InputTab('4')">
            <svg-icon :icon-class="activeInput == '4' ? 'ai_mindMap' : 'ai_mindMaps'" class="size_icon"></svg-icon>脑图
          </div>
          <div class="talk-tab" :class="{ 'activeTab': activeInput == '5' }" @click="InputTab('5')">
            <svg-icon :icon-class="activeInput == '5' ? 'ai_ocr' : 'ai_ocrs'" class="size_icon"></svg-icon>OCR
          </div>
          <div class="talk-tab" :class="{ 'activeTab': activeInput == '6' }" @click="InputTab('6')">
            <svg-icon :icon-class="activeInput == '6' ? 'ai_note' : 'ai_notes'" class="size_icon"></svg-icon>笔记
          </div>

          <div class="talk-tab" :class="{ 'activeTab': activeInput == '7' }" @click="InputTab('7')">
            <el-dropdown @command="graphicCommand" trigger="click">
              <div class="talktab" :class="{ 'svgact': activeInput == '7' }">
                <svg-icon :icon-class="activeInput == '7' ? 'ai_graphic' : 'ai_graphics'" class="size_icon"></svg-icon>图示
              </div>

              <template #dropdown>
                <el-dropdown-menu>
                  <el-dropdown-item command="process">
                    <span>流程图</span>
                  </el-dropdown-item>

                  <el-dropdown-item command="time">
                    <span>时序图</span>
                  </el-dropdown-item>

                  <el-dropdown-item command="state">
                    <span>状态图</span>
                  </el-dropdown-item>

                  <el-dropdown-item command="relation">
                    <span>关系图</span>
                  </el-dropdown-item>
                  <el-dropdown-item command="category">
                    <span>类 图</span>
                  </el-dropdown-item>
                </el-dropdown-menu>
              </template>
            </el-dropdown>
          </div>

          <div class="talk-tab" :class="{ 'activeTab': activeInput == '8' }" @click="InputTab('8')">
            <el-dropdown @command="checkCommand" trigger="click">
              <div class="talktab" :class="{ 'svgact': activeInput == '8' }">
                <svg-icon :icon-class="activeInput == '8' ? 'ai_checks' : 'ai_check'" class="size_icon"></svg-icon>校审
              </div>
              <template #dropdown>
                <el-dropdown-menu>
                  <el-dropdown-item command="spell">
                    <span>拼写检查</span>
                  </el-dropdown-item>

                  <el-dropdown-item command="risk">
                    <span>风险检查</span>
                  </el-dropdown-item>

                  <el-dropdown-item command="text">
                    <span>文档对比</span>
                  </el-dropdown-item>
                </el-dropdown-menu>
              </template>
            </el-dropdown>
          </div>

          <div class="talk-tab" :class="{ 'activeTab': activeInput == '9' }" @click="InputTab('9')">
            <el-dropdown @command="moreCommand" trigger="click">
              <div class="talktab" :class="{ 'svgact': activeInput == '9' }">
                <svg-icon :icon-class="activeInput == '9' ? 'ai_mores' : 'ai_more'" class="size_icon"></svg-icon>更多
              </div>

              <template #dropdown>
                <el-dropdown-menu>
                  <el-dropdown-item command="translate">
                    <span>翻译</span>
                  </el-dropdown-item>

                  <!-- <el-dropdown-item command="rewrite">
                    <span>改写</span>
                  </el-dropdown-item> -->

                  <!-- <el-dropdown-item command="extract">
                    <span>抽取</span>
                  </el-dropdown-item> -->
                  <el-dropdown-item class="Dropdown_item_menu" command="">
                    <el-dropdown placement="left-start" trigger="hover" @command="moreHandleCommand">
                      <div class="el-dropdown-link personalization">
                        <div style="display: flex; align-items: center">
                          <span>抽取</span>
                        </div>
                        <el-icon><CaretRight /></el-icon>
                      </div>

                      <template #dropdown>
                        <el-dropdown-menu>
                          <el-dropdown-item class="Dropdown_item_menu" command="templateLibrary"> 合同抽取 </el-dropdown-item>

                          <el-dropdown-item class="Dropdown_item_menu" command="publicTemplateLibrary"> 招标文件抽取 </el-dropdown-item>

                          <el-dropdown-item class="Dropdown_item_menu" command="enterpriseLabel"> 自定义抽取 </el-dropdown-item>
                        </el-dropdown-menu>
                      </template>
                    </el-dropdown>
                  </el-dropdown-item>
                </el-dropdown-menu>
              </template>
            </el-dropdown>
          </div>

          <!-- <div class="talk-tab" :class="{ 'activeTab': activeInput == '7' }" @click="InputTab('7')">
            <svg-icon icon-class="ai_graphic" class="size_icon"></svg-icon>图示
          </div> -->

          <!-- <div class="talk-tab" :class="{ 'activeTab': activeInput == '8' }" @click="InputTab('8')">
            <svg-icon icon-class="ai_check" class="size_icon"></svg-icon>校审
          </div> -->
        </div>

        <!-- 文档AI问答 -->
        <transition name="fade" @before-enter="beforeEnter" @enter="enter" @leave="leave" v-if="activeInput == '1'">
          <div class="page_File" :style="fileStyle">
            <div class="chat-container" :style="chatHeight">
              <div class="chat-messages" ref="chatMessages" v-if="messages.length">
                <div v-for="(message, index) in messages" :key="index">
                  <!-- 如果是用户消息 -->
                  <div v-if="message.isUser" class="user-message">
                    <div class="messageisUser">
                      <div class="message-content user">
                        <span>{{ message.content }}</span>
                      </div>
                      <img class="avatarUser" :src="userStore.avatar" alt="暂无" />
                    </div>
                  </div>

                  <!-- 如果是AI（或其他）消息 -->
                  <div v-else class="ai-message">
                    <div class="message-content-wrapper">
                      <svg-icon icon-class="ai_chat2" class="AIavatar"></svg-icon>
                      <div class="message-content show_box">
                        <div class="others">
                          <!-- 如果是 loading 状态 -->
                          <!-- <span v-if="message.isLoading" class="loading-text">加载中...</span> -->
                          <!-- 如果不是 loading，显示实际消息 -->
                          <MdPreview
                            v-if="messages.length"
                            :id="message?.id"
                            :modelValue="message.content"
                            :previewTheme="MdEditorV3State.theme"
                            :codeTheme="MdEditorV3State.codeTheme"
                          />

                          <MdCatalog v-if="messages.length" :editorId="message?.id" :scrollElement="scrollElement" />
                          <!-- <div style="letter-spacing: 2px" v-html="marked(message.content.trim())" v-highlight></div> -->
                          <!-- <span v-else style="letter-spacing: 2px">{{ message.content }}</span> -->

                          <div v-show="isStart && index == messages.length - 1" class="stop_box">
                            <icon-loading style="color: #e67e22; font-size: 20px" />
                            <el-tag type="danger" class="stop_icon" @click="stopTextClick">
                              <svg-icon icon-class="stop"></svg-icon>
                              停止回答
                            </el-tag>
                          </div>
                        </div>

                        <!-- 重新回答和复制 v-if="!msgLoading && index == chatList.length - 1"-->
                        <div v-if="!isStart" class="list_foot" :class="message.isAudio != 'play' ? 'last_foot_visible' : ''" ref="listFootRef">
                          <div title="播放音频" v-if="message.isAudio == 'play'" class="div_icon div_icon_volume" @click="playAudioClick(message)">
                            <svg-icon icon-class="volume"></svg-icon>
                          </div>
                          <div title="暂停音频" v-else class="div_icon div_icon_volume" @click="pauseAudioClick(message)">
                            <svg-icon icon-class="pause" style="color: #f08f00"></svg-icon>
                          </div>
                          <div title="重新回答" class="div_icon" @click="reanswerClick(message, index)">
                            <el-icon>
                              <Refresh />
                            </el-icon>
                          </div>
                          <div title="复制" class="div_icon" @click="copyClick(message.content)">
                            <el-icon>
                              <CopyDocument />
                            </el-icon>
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
                </div>
              </div>

              <!-- <div class="chat-messages" ref="chatMessages" v-if="!messages.length">
                <el-empty description="暂无文档问答内容" />
              </div> -->
            </div>
          </div>
        </transition>

        <!-- 文档总结 -->
        <transition name="fade" @before-enter="beforeEnter" @enter="enter" @leave="leave" v-if="activeInput === '2'">
          <div class="page_File textFile" :style="summaryStyle">
            <div class="chat-container" :style="summaryHeight">
              <div class="chat-messages" ref="chatMessages" v-if="summaryMessages.length">
                <div v-for="(summaryMessages, index) in summaryMessages" :key="index">
                  <!-- 如果是用户消息 -->
                  <div v-if="summaryMessages.isUser" class="user-message">
                    <div class="messageisUser">
                      <div class="message-content user">
                        <span>{{ summaryMessages.content }}</span>
                      </div>
                      <img class="avatarUser" :src="userStore.avatar" alt="暂无" />
                    </div>
                  </div>

                  <!-- 如果是AI（或其他）消息 -->
                  <div v-else class="ai-message">
                    <div class="message-content-wrapper">
                      <svg-icon icon-class="ai_chat2" class="summaryAvatar"></svg-icon>
                      <div class="message-content other">
                        <!-- 如果是 loading 状态 -->
                        <span v-if="summaryMessages.isLoading" class="loading-text">加载中...</span>
                        <!-- 如果不是 loading，显示实际消息 -->
                        <span v-else style="letter-spacing: 2px">{{ summaryMessages.content }}</span>
                      </div>
                    </div>
                  </div>
                </div>
              </div>

              <div class="chat-messages" ref="chatMessages" v-if="!summaryMessages.length">
                <el-empty description="暂无总结内容" />
              </div>
            </div>
          </div>
        </transition>

        <!-- 文档翻译 -->
        <transition name="fade" @before-enter="beforeEnter" @enter="enter" @leave="leave" v-if="moretab === 'translate'">
          <div class="page_File textFile" :style="summaryStyle">
            <div class="chat-container" :style="summaryHeight">
              <div class="chat-messages" ref="chatMessages" v-if="translationMessages.length">
                <div v-for="(translationMessages, index) in translationMessages" :key="index">
                  <!-- 如果是用户消息 -->
                  <div v-if="translationMessages.isUser" class="user-message">
                    <div class="messageisUser">
                      <div class="message-content user">
                        <span>{{ translationMessages.content }}</span>
                      </div>
                      <img class="avatarUser" :src="userStore.avatar" alt="暂无" />
                    </div>
                  </div>

                  <!-- 如果是AI（或其他）消息 -->
                  <div v-else class="ai-message">
                    <div class="message-content-wrapper">
                      <svg-icon icon-class="ai_chat2" class="summaryAvatar"></svg-icon>
                      <div class="message-content other">
                        <!-- 如果是 loading 状态 -->
                        <span v-if="translationMessages.isLoading" class="loading-text">加载中...</span>
                        <!-- 如果不是 loading，显示实际消息 -->
                        <span v-else style="letter-spacing: 2px">{{ translationMessages.content }}</span>
                      </div>
                    </div>
                  </div>
                </div>
              </div>

              <div class="chat-messages" ref="chatMessages" v-if="!translationMessages.length">
                <el-empty description="暂无翻译内容" />
              </div>
            </div>
          </div>
        </transition>

        <!-- 预览脑图-->
        <div class="chatMap" v-if="activeInput === '4'" :style="summaryStyle">
          <Previewmap ref="PreviewmapRefs" :mapVla="mapVla" />
        </div>

        <!-- 图示部分-->
        <div v-show="activeInput === '7'" class="mermaid_box">
          <!-- 流程图-->
          <div class="mermaids" v-if="graphicTab == 'process'" :style="processStyle">
            <PreviewMermaid ref="PreviewMermaidRefs" @getAiTranslate="getAiTranslate" />
          </div>

          <!-- 时序图 -->
          <div class="mermaids" v-if="graphicTab == 'time'" :style="processStyle">
            <TimeSequence ref="TimeSequenceRefs" @getAiTime="getAiTime" />
          </div>

          <!-- 状态图 -->
          <div class="mermaids" v-if="graphicTab == 'state'" :style="processStyle">
            <StateMermaid ref="StateMermaidRefs" @getAiState="getAiState" />
          </div>

          <!-- 关系图 -->
          <div class="mermaids" v-if="graphicTab == 'relation'" :style="processStyle">
            <RelationMermaid ref="RelationMermaidRefs" @getAiRelation="getAiRelation" />
          </div>

          <!-- 类图 -->
          <div class="mermaids" v-if="graphicTab == 'category'" :style="processStyle">
            <CategoryMermaid ref="CategoryMermaidRefs" @getAiCategory="getAiCategory" />
          </div>

          <div class="mermaids" v-if="graphicTab == null" :style="processNone">
            <el-empty description="暂无图示内容,请选择" />
          </div>
        </div>

        <!-- ocr-->
        <div v-if="activeInput === '5'" class="mermaid_box" style="height: 'calc(100vh - 146px)'; overflow: auto">
          <Previewzzzz ref="previewRefs" />
        </div>

        <!-- 文档抽取 -->
        <transition name="fade" @before-enter="beforeEnter" @enter="enter" @leave="leave" v-if="moretab === 'extract'">
          <div class="page_File" :style="summaryStyle">
            <div class="chat-container" :style="summaryHeight">
              <div class="chat-messages" ref="chatMessages" v-if="extractMsg.length">
                <div v-for="(msg, index) in extractMsg" :key="index">
                  <!-- 如果是用户消息 -->
                  <div v-if="msg.isUser" class="user-message">
                    <div class="messageisUser">
                      <div class="message-content user">
                        <span>{{ msg.content }}</span>
                      </div>
                      <img class="avatarUser" :src="userStore.avatar" alt="暂无" />
                    </div>
                  </div>

                  <!-- 如果是AI（或其他）消息 -->
                  <div v-else class="ai-message">
                    <div class="message-content-wrapper">
                      <svg-icon icon-class="ai_chat2" class="AIavatar"></svg-icon>
                      <div class="message-content show_box">
                        <div class="other">
                          <!-- 如果是 loading 状态 -->
                          <!-- <span v-if="message.isLoading" class="loading-text">加载中...</span> -->
                          <!-- 如果不是 loading，显示实际消息 -->
                          <MdPreview
                            :id="msg?.id"
                            :modelValue="msg.content"
                            :previewTheme="MdEditorV3State.theme"
                            :codeTheme="MdEditorV3State.codeTheme"
                          />

                          <MdCatalog :editorId="msg?.id" :scrollElement="scrollElement" />
                          <!-- <div style="letter-spacing: 2px" v-html="marked(message.content.trim())" v-highlight></div> -->
                          <!-- <span v-else style="letter-spacing: 2px">{{ message.content }}</span> -->

                          <div v-show="isExtract && index == extractMsg.length - 1" class="stop_box">
                            <icon-loading style="color: #e67e22; font-size: 20px" />
                            <el-tag type="danger" class="stop_icon" @click="stopTextClick">
                              <svg-icon icon-class="stop"></svg-icon>
                              停止回答
                            </el-tag>
                          </div>
                        </div>

                        <!-- 重新回答和复制 v-if="!msgLoading && index == chatList.length - 1"-->
                        <div v-if="!isExtract" class="list_foot" :class="msg.isAudio != 'play' ? 'last_foot_visible' : ''" ref="listFootRef">
                          <div title="播放音频" v-if="msg.isAudio == 'play'" class="div_icon div_icon_volume" @click="playAudioClick(msg)">
                            <svg-icon icon-class="volume"></svg-icon>
                          </div>
                          <div title="暂停音频" v-else class="div_icon div_icon_volume" @click="pauseAudioClick(msg)">
                            <svg-icon icon-class="pause" style="color: #f08f00"></svg-icon>
                          </div>
                          <div title="重新回答" class="div_icon" @click="reanswerClick(msg, index)">
                            <el-icon>
                              <Refresh />
                            </el-icon>
                          </div>
                          <div title="复制" class="div_icon" @click="copyClick(msg.content)">
                            <el-icon>
                              <CopyDocument />
                            </el-icon>
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
                </div>
              </div>

              <div class="chat-messages" ref="chatMessages" v-if="!extractMsg.length">
                <el-empty description="暂无文档抽取内容" />
              </div>
            </div>
          </div>
        </transition>

        <!-- 输入框部分 -->
        <div class="page_input" v-if="activeInput == '1'">
          <div class="input_box">
            <el-input
              ref="textInputRefs"
              v-model="inputMsg"
              :autosize="{ minRows: 3, maxRows: 5 }"
              type="textarea"
              resize="none"
              placeholder="请输入内容"
              @keyup.ctrl.enter.native="handleKeyPress"
              @keydown.enter.exact.native="enterSubmit"
              @input="sendTextInput"
            ></el-input>

            <div class="btn_box">
              <div class="voice_box" title="语音输入">
                <img
                  v-if="isSpeakType == 1"
                  src="../../../assets/images/chatgpt/mic.png"
                  style="width: 17px; height: 20px"
                  alt=""
                  @click="startRecordAudio"
                />
                <div v-else-if="isSpeakType == 2">
                  <div class="loaderRectangle" @click="stopRecordAudio">
                    <div></div>
                    <div></div>
                    <div></div>
                    <div></div>
                    <div></div>
                  </div>
                </div>

                <div v-else-if="isSpeakType == 3" class="SpeakType3">
                  <i class="el-icon-loading"></i>
                  <span>转码中...</span>
                </div>
              </div>

              <el-divider direction="vertical" />
              <!-- 发送按钮 -->
              <div class="sendBtn" title="发送" @click="sendText">
                <svg-icon icon-class="send1"></svg-icon>
              </div>
            </div>
          </div>
        </div>

        <!-- 提示 -->
        <div class="tips">服务生成的所有内容均由人工智能模型生成，其生成内容的准确性和完整性无法保证，不代表我们的态度或观点</div>
      </div>

      <!-- 文件上传部分 -->
      <div class="fileup" :class="{ 'full-radius': Listfile.length == 0, 'bottom-right-radius': Listfile.length != 0 }" v-if="!isChat">
        <div class="info">
          <p class="title">文档解析</p>
          <p class="desc">深入文档,快速理解,精准获取海量信息</p>

          <!-- 文件部分 -->
          <div class="file">
            <!-- 文件展示部分 -->
            <div class="file-list" v-if="Listfile.length > 0" v-loading="Isloading">
              <div class="file-item" slot="file" :slot-scope="{ filedow }">
                <svg-icon icon-class="fork" class="fork-icon" @click="forkRemove(filedow)"></svg-icon>
                <div class="file-box">
                  <div class="file-icon">
                    <svg-icon :icon-class="selectSvgIcons(filedow)" class="icon_file"></svg-icon>
                  </div>

                  <div class="file-name">
                    <span class="file_name">
                      {{ filedow && filedow.fileName ? (filedow.fileName.length > 9 ? filedow.fileName.slice(0, 9) + '...' : filedow.fileName) : '' }}
                    </span>
                    <!-- <span class="file_name">{{ filedow.fileName }} </span> -->
                    <span class="file-size">{{ formatSize(filedow.size) }}</span>
                  </div>
                </div>
              </div>
            </div>

            <!-- 点击上传 -->
            <div class="file-upload">
              <!-- 图标部分 -->
              <div class="icon">
                <div class="icons_box">
                  <svg-icon icon-class="Pdf" class="svgicon"></svg-icon>
                </div>
                <div class="icons_boxs">
                  <svg-icon icon-class="Excel" class="svgicon"></svg-icon>
                </div>
                <div class="icons_box">
                  <svg-icon icon-class="Word" class="svgicon"></svg-icon>
                </div>
              </div>

              <p class="txt">上传文件开始问答</p>
              <p class="desc-file">点击上传文件,支持PDF/WORD/EXCEL,单个文件大小不超过30MB</p>
              <div>
                <el-upload
                  accept=".docx,doc,.xlsx,.ppt,.pdf"
                  class="upload-demo"
                  :auto-upload="false"
                  action="/"
                  :on-change="handlePreview"
                  :on-remove="handleRemove"
                  :before-remove="beforeRemove"
                  :before-upload="beforeUpload"
                  multiple
                  :limit="1"
                  :on-exceed="handleExceed"
                  :file-list="Listfile"
                  ref="uploadRef"
                  :show-file-list="false"
                >
                  <div class="upload-btn">
                    <span>上传文档</span>
                  </div>
                </el-upload>
              </div>
            </div>
          </div>

          <!-- <div class="start" @click="startChat">开始问答</div> -->
        </div>
      </div>
    </div>
  </div>
</template>

<script lang="ts" setup>
const msgLoading = ref(false);

import { marked } from 'marked';
import mermaid from 'mermaid'; //引用mermaid
const pdfUrl = ref('http://storage.xuetangx.com/public_assets/xuetangx/PDF/PlayerAPI_v1.0.6.pdf');
import { MoreFilled, Delete, Position, MessageBox, Download, Star, Back } from '@element-plus/icons-vue';
import { debounce, throttle } from '@/utils/yuUtils.js';
import onlinePreviewApi from '@/api/onlinePreview/onlinePreviewApi';
import PreviewPdf from '@/views/personDoc/AiFile/preview-pdf.vue'; //预览pdf组件
import Previewmap from '@/views/personDoc/AiFile/components/preview-map.vue'; //导图预览
import PreviewMermaid from '@/views/personDoc/AiFile/components/preview-mermaid.vue'; //流程图预览
import TimeSequence from '@/views/personDoc/AiFile/components/time-sequence.vue'; //时序预览
import StateMermaid from '@/views/personDoc/AiFile/components/state-mermaid.vue'; //状态图预览
import RelationMermaid from '@/views/personDoc/AiFile/components/relation-mermaid.vue'; //关系图预览
import CategoryMermaid from '@/views/personDoc/AiFile/components/category-mermaid.vue'; //类图预览

// ocr
import Previewzzzz from '../../home/components/editor/Preview.vue';
import yzpTest from '@/views/yzp-test.vue'; //测试文件
import { getToken } from '@/utils/auth';
import {
  ApiAIDocumentary,
  ApiAIfileChat,
  ApiAIHistory,
  ApiAIHistoryAddorEdit,
  ApiAIHistoryId,
  ApiAIHistorydelOnly,
  ApiAIHistorydelMany,
  ApiAImarkDown,
  ApiAIflowChart
} from '@/api/personDoc/aiApi';
import { defineProps, onMounted, ref, reactive } from 'vue';
import { ApiTempOrdinary, ApiTempverifyData } from '@/api/personDoc/tempApi';
const emit: any = defineEmits(['getAiTranslate', 'getAiTime', 'getAiState', 'getAiRelation', 'getAiCategory']);
import { MdPreview, MdCatalog } from 'md-editor-v3';
import 'md-editor-v3/lib/preview.css';
const scrollElement = document.documentElement;
/**Markdown编辑器 */
const MdEditorV3State = reactive({
  theme: 'github',
  codeTheme: 'github'
});

const font = reactive({
  color: 'rgba(0, 0, 0, .15)'
});
const listFootRef = ref<HTMLElement | null>(null);
const watermarkTxt = ref('');
/**停止接口请求,停止回答 */
const controller = ref(new AbortController());

const iframeLoading = ref(false);

const { proxy } = getCurrentInstance() as any;

const Pdfloading = ref(true); // loading效果
/***********************************ai文档 start */
const isContextShow = ref(false); //语境中心消息显示
const isSpeakType = ref(1); //1:静默状态,还未点击开始录音,2:开始录音,3:结束录音,正在转换中

const inputMsg = ref('');
const showHight = ref(false);
const isQa = ref(false);
const markId = ref(null); //文件id
const mapVla = ref(null); //转为导图的文件内容

/*********************************增加部分start */
const msgFile = ref([]); //文件问答
const moretab = ref(null); //更多tab选择

const isStart = ref(false);
const chatListId = ref(''); //聊天记录的id
const chatTxt = ref('');
const chatList = ref([]); //聊天列表
const isChat = ref(true);
const Isloading = ref(false);
const selectedIndex = ref(null); // 用来记录当前选中的历史记录项
const onlineSrc = ref('');
const isExtract = ref(false);

// 返回
const goBack = () => {
  Listfile.value = [];
  isChat.value = false;
  headerStyle.value.width = '0px';
  summaryMessages.value = [];
  translationMessages.value = [];
  extractMsg.value = [];
  MermaidVla.value = null;
  mapVla.value = null;
  messages.value = [];
  filedow.value = '';
  activeInput.value = '1';
  fileInfo.value = '';
  graphicTab.value = null;
  PreviewMermaidRefs.value = null;
  PreviewmapRefs.value = null;
  TimeSequenceRefs.value = null;
  TimeVla.value = null;
  StateMermaidRefs.value = null;
  StateVla.value = null;
  RelationMermaidRefs.value = null;
  RelationVla.value = null;
  CategoryMermaidRefs.value = null;
  CategoryVla.value = null;
  stopTextClick();
  // isChat;
};

const headerStyle = ref({
  width: '0px' // 初始高度
});

const Styleheader = ref({
  // height: 'calc(95vh - 10px)' // 初始高度
  height: 'calc(99vh - 10px)' // 初始高度
});

const boderStyle = ref({
  borderRight: '1px solid #615ced4f'
});

const inputStyle = ref({
  height: 'calc(99vh - 40px)'
  // height: 'calc(95vh - 15px)'
});

const summaryStyle = ref({
  height: 'calc(100vh - 146px)' /* 最大高度 */
});

const processStyle = ref({
  height: 'calc(100vh - 237px)' /* 最大高度 */
});
const processNone = ref({
  height: 'calc(100vh - 220px)' /* 最大高度 */
});

const fileStyle = ref({
  height: 'calc(94vh - 205px)' /* 最大高度 */
});

const chatHeight = ref({
  height: 'calc(94vh - 225px)' /* 最大高度 */
});

const summaryHeight = ref({
  height: 'calc(94vh - 145px)' /* 最大高度 */
});

const Noinput = ref({
  height: 'calc(94vh - 130px)' /* 最大高度 */
});

const activeInput = ref('1');
const historyList = ref([]);
import axios from 'axios';
import Recorder from 'js-audio-recorder';
// 定义Recorder对象
const recorder: any = new Recorder({
  sampleBits: 16, // 采样位数，支持 8 或 16，默认是16
  sampleRate: 16000, // 采样率，支持 11025、16000、22050、24000、44100、48000，根据浏览器默认值，我的chrome是48000
  numChannels: 1 // 声道，支持 1 或 2， 默认是1
  // compiling: false,(0.x版本中生效,1.x增加中)  // 是否边录边转换，默认是false
});
const router = useRouter();
import { useRoute } from 'vue-router';
const route = useRoute(); // 获取路由信息
const textInputRefs = ref();
onMounted(() => {
  isChat.value = false;
});

//开始问答（文档）
const startChat = () => {
  if (Listfile.value.length > 0) {
    isChat.value = true;
  } else {
    proxy.$modal.msgWarning('请先上传文件');
  }
};

//查询历史记录
const getHistory = () => {
  ApiAIHistory().then((res) => {
    if (res.code == 200) {
      historyList.value = res.data;
    }
  });
};

// 保存和修改历史记录
const saveHistory = () => {
  // 整理历史消息，去除正在加载的消息
  const history = messages.value
    .filter((message) => !message.isLoading) // 去除正在加载的消息
    .map((message) => ({
      role: message.isUser ? 'user' : 'assistant', // 根据 role 进行分类
      content: message.isUser
        ? message.content // 用户消息直接取 message.content
        : message.content || TranslateInfo.value // AI 回复，先尝试取 message.content，如果没有，则取 TranslateInfo.value
    }));

  let oParam = {
    chatId: chatListId.value || null, //第一次是没有id的,有了id就传id
    title: chatTxt.value || null, //有id就传，没有就传空
    chatHistoryDtoList: history || null
  };

  ApiAIHistoryAddorEdit(oParam).then((res) => {
    if (res.code == 200) {
      chatListId.value = res.data.chatId;
      chatTxt.value = res.data.title;

      getHistory();
    }
  });
};

const previewRefs = ref(null);

// 头部
const InputTab = debounce((tab) => {
  // 在切换 tab 时清空消息内容
  if (tab !== activeInput.value) {
    moretab.value = null; // 清空消息
    pauseAudioClick();
  }

  if (Listfile.value.length > 0) {
    activeInput.value = tab;
    if (tab == '2') {
      //文档的总结
      if (summaryMessages.value.length > 0) {
        return;
      } else {
        fileSummary();
      }
    }

    if (tab == '4') {
      if (markId.value) {
        //文档导图(脑图)
        getFilemark();
      }
    }

    if (tab == '5') {
      //文档翻译
      getFilemark();
      setTimeout(() => {
        previewRefs.value.upDataOcr(mapVla.value);
      }, 1000);
    }
  } else {
    proxy.$modal.msgWarning('请先上传文件');
  }
}, 500);

const graphicTab = ref(null);
const MermaidVla = ref(null); //流程图数据
const PreviewMermaidRefs = ref();
const PreviewmapRefs = ref();
const TimeSequenceRefs = ref(); //时序图
const TimeVla = ref(null); //时序图数据
const StateMermaidRefs = ref(); //状态图
const StateVla = ref(null); //状态图数据
const RelationMermaidRefs = ref(); //关系图
const RelationVla = ref(null); //关系图数据
const CategoryMermaidRefs = ref(); //类图
const CategoryVla = ref(null); //类数据

//图示
const graphicCommand = (command: any) => {
  // 流程图
  if (command == 'process') {
    graphicTab.value = 'process';
    if (MermaidVla.value && MermaidVla.value.length > 0) {
      let TranslateTxt = sessionStorage.getItem('Translate');
      nextTick(() => {
        PreviewMermaidRefs.value.initMermaidFunc(TranslateTxt);
      });
      return;
    } else {
      nextTick(() => {
        getAiTranslate();
      });
    }
  }

  // // 时序图
  // if (command == 'time') {
  //   graphicTab.value = 'time';
  //   if (TimeVla.value && TimeVla.value.length > 0) {
  //     let timeTxt = sessionStorage.getItem('time');
  //     TimeSequenceRefs.value.initMermaidTime(timeTxt);
  //     return;
  //   } else {
  //     nextTick(() => {
  //       getAiTime();
  //     });
  //   }
  // }

  // // 状态图
  // if (command == 'state') {
  //   graphicTab.value = 'state';
  //   if (StateVla.value && StateVla.value.length > 0) {
  //     let StateTxt = sessionStorage.getItem('State');
  //     StateMermaidRefs.value.initMermaidState(StateTxt);
  //     return;
  //   } else {
  //     nextTick(() => {
  //       getAiState();
  //     });
  //   }
  // }

  // // 关系图
  // if (command == 'relation') {
  //   graphicTab.value = 'relation';
  //   if (RelationVla.value && RelationVla.value.length > 0) {
  //     let RelationTxt = sessionStorage.getItem('Relation');
  //     RelationMermaidRefs.value.initMermaidRelation(RelationTxt);
  //     return;
  //   } else {
  //     nextTick(() => {
  //       getAiRelation();
  //     });
  //   }
  // }

  // // 类图
  // if (command == 'category') {
  //   graphicTab.value = 'category';
  //   if (CategoryVla.value && CategoryVla.value.length > 0) {
  //     let CategoryTxt = sessionStorage.getItem('Category');

  //     CategoryMermaidRefs.value.initMermaidCategory(CategoryTxt);
  //     return;
  //   } else {
  //     nextTick(() => {
  //       getAiCategory();
  //     });
  //   }
  // }

  console.log('🚀 ~ graphicCommand ~ command:图示', command);
};

// 流程图接口请求
const getAiTranslate = async () => {
  let oParam = {
    fileName: filedow.value.fileName,
    fileType: Listfile.value[0].name.split('.').pop() || ''
  };
  // 构造查询字符串
  const queryParams = new URLSearchParams(oParam).toString();

  await fetch(`${import.meta.env.VITE_APP_BASE_API}/aiqa/personal/chat/flowChart?${queryParams}`, {
    method: 'GET', // 保持 'GET' 请求
    headers: {
      Authorization: 'Bearer ' + getToken(),
      'Content-Type': 'application/json',
      clientid: import.meta.env.VITE_APP_CLIENT_ID
    }
  })
    .then((response) => response)
    .then(async (response) => {
      const reader = response.body.getReader();
      const decoder = new TextDecoder();

      while (1) {
        const { done, value } = await reader.read();
        if (done) {
          return;
        }

        const text = decoder.decode(value, { stream: true });
        // PreviewMermaidRefs.value.mermaidCode = `${text}`;

        MermaidVla.value = text;
        sessionStorage.setItem('Translate', MermaidVla.value);
        nextTick(() => {
          PreviewMermaidRefs.value.initMermaidFunc(text);
        });
      }
    })
    .catch((error) => {
      console.error('Error:', error);
    });
};

//时序图接口请求
const getAiTime = async () => {
  let oParam = {
    fileName: filedow.value.fileName,
    fileType: Listfile.value[0].name.split('.').pop() || ''
  };
  // 构造查询字符串
  const queryParams = new URLSearchParams(oParam).toString();

  await fetch(`${import.meta.env.VITE_APP_BASE_API}/aiqa/personal/chat/timingDiagram?${queryParams}`, {
    method: 'GET', // 保持 'GET' 请求
    headers: {
      Authorization: 'Bearer ' + getToken(),
      'Content-Type': 'application/json',
      clientid: import.meta.env.VITE_APP_CLIENT_ID
    }
  })
    .then((response) => response)
    .then(async (response) => {
      const reader = response.body.getReader();
      const decoder = new TextDecoder();

      while (1) {
        const { done, value } = await reader.read();
        if (done) {
          return;
        }

        const text = decoder.decode(value, { stream: true });
        TimeVla.value = text;
        sessionStorage.setItem('time', TimeVla.value);

        nextTick(() => {
          TimeSequenceRefs.value.initMermaidTime(text);
        });
      }
    })
    .catch((error) => {
      console.error('Error:', error);
    });
};

//状态图接口请求
const getAiState = async () => {
  let oParam = {
    fileName: filedow.value.fileName,
    fileType: Listfile.value[0].name.split('.').pop() || ''
  };
  // 构造查询字符串
  const queryParams = new URLSearchParams(oParam).toString();

  await fetch(`${import.meta.env.VITE_APP_BASE_API}/aiqa/personal/chat/stateDiagram?${queryParams}`, {
    method: 'GET', // 保持 'GET' 请求
    headers: {
      Authorization: 'Bearer ' + getToken(),
      'Content-Type': 'application/json',
      clientid: import.meta.env.VITE_APP_CLIENT_ID
    }
  })
    .then((response) => response)
    .then(async (response) => {
      const reader = response.body.getReader();
      const decoder = new TextDecoder();

      while (1) {
        const { done, value } = await reader.read();
        if (done) {
          return;
        }

        const text = decoder.decode(value, { stream: true });
        StateVla.value = text;
        sessionStorage.setItem('State', StateVla.value);

        StateMermaidRefs.value.initMermaidState(text);
      }
    })
    .catch((error) => {
      console.error('Error:', error);
    });
};

//关系图接口请求
const getAiRelation = async () => {
  let oParam = {
    fileName: filedow.value.fileName,
    fileType: Listfile.value[0].name.split('.').pop() || ''
  };
  // 构造查询字符串
  const queryParams = new URLSearchParams(oParam).toString();

  await fetch(`${import.meta.env.VITE_APP_BASE_API}/aiqa/personal/chat/entityRelationshipDiagram?${queryParams}`, {
    method: 'GET', // 保持 'GET' 请求
    headers: {
      Authorization: 'Bearer ' + getToken(),
      'Content-Type': 'application/json',
      clientid: import.meta.env.VITE_APP_CLIENT_ID
    }
  })
    .then((response) => response)
    .then(async (response) => {
      const reader = response.body.getReader();
      const decoder = new TextDecoder();

      while (1) {
        const { done, value } = await reader.read();
        if (done) {
          return;
        }

        const text = decoder.decode(value, { stream: true });

        RelationVla.value = text;
        sessionStorage.setItem('Relation', RelationVla.value);
        RelationMermaidRefs.value.initMermaidRelation(text);
      }
    })
    .catch((error) => {
      console.error('Error:', error);
    });
};

//类图接口请求
const getAiCategory = async () => {
  let oParam = {
    fileName: filedow.value.fileName,
    fileType: Listfile.value[0].name.split('.').pop() || ''
  };
  // 构造查询字符串
  const queryParams = new URLSearchParams(oParam).toString();

  await fetch(`${import.meta.env.VITE_APP_BASE_API}/aiqa/personal/chat/classDiagram?${queryParams}`, {
    method: 'GET', // 保持 'GET' 请求
    headers: {
      Authorization: 'Bearer ' + getToken(),
      'Content-Type': 'application/json',
      clientid: import.meta.env.VITE_APP_CLIENT_ID
    }
  })
    .then((response) => response)
    .then(async (response) => {
      const reader = response.body.getReader();
      const decoder = new TextDecoder();

      while (1) {
        const { done, value } = await reader.read();
        if (done) {
          return;
        }

        const text = decoder.decode(value, { stream: true });
        CategoryVla.value = text;
        sessionStorage.setItem('Category', CategoryVla.value);
        CategoryMermaidRefs.value.initMermaidCategory(text);
      }
    })
    .catch((error) => {
      console.error('Error:', error);
    });
};

//校审
const checkCommand = (command: any) => {
  console.log('🚀 ~ checkCommand ~ command:校审', command);
};

// 更多
const moreCommand = (command: any) => {
  //文档翻译
  if (command == 'translate') {
    moretab.value = 'translate';
    if (translationMessages.value.length > 0) {
      return;
    } else {
      fileTranslate();
    }
  }
  //文档抽取
  if (command == 'extract') {
    moretab.value = 'extract';
    if (extractMsg.value.length > 0) {
      return;
    } else {
      console.log('文档抽取', Listfile.value[0].name.split('.').pop() || '');
      console.log('文档抽取filedow.value', filedow.value.suffix);
    }
  }
  console.log('🚀 ~ moreCommand ~ command:更多', command);
};

const moreHandleCommand = (command: any) => {};
// 独立存储总结和翻译的消息
const summaryMessages = ref([]);
const summaryInfo = ref('');
const translationMessages = ref([]);
const translationInfo = ref('');
const extractMsg = ref([]); //文档抽取

//文档抽取
const fileExtract = debounce(async () => {
  let oParam = {
    prompt: fileInfo.value
  };

  // 立即将用户消息和加载中的 AI 消息添加到消息列表
  addUserMessage(null, 'Extract');
  inputMsg.value = ''; // 清空输入框
}, 500);

//文档的总结
const fileSummary = debounce(async () => {
  let oParam = {
    prompt: fileInfo.value
  };

  // 立即将用户消息和加载中的 AI 消息添加到消息列表
  addUserMessage(null, 'summary');
  inputMsg.value = ''; // 清空输入框

  // 发送请求获取 AI 响应
  await fetch(`${import.meta.env.VITE_APP_BASE_API}/aiqa/personal/chat/documentary/file/summarize`, {
    method: 'POST',
    headers: {
      Authorization: 'Bearer ' + getToken(), // 使用 Bearer Token 认证
      'Content-Type': 'application/json', // 请求体为 JSON
      clientid: import.meta.env.VITE_APP_CLIENT_ID // 客户端 ID
    },
    body: JSON.stringify(oParam) // 请求体参数
  } as any)
    .then((response: any) => {
      return response;
    })
    .then(async (response: any) => {
      const reader = response.body.getReader(); // 获取响应的 body 流
      const decoder = new TextDecoder(); // 创建一个解码器，用于将字节流转换为文本
      let accumulatedData = ''; // 用于累积收到的数据
      let isMessageStarted = false; // 标记是否开始接收有效的消息
      let isMessageEnded = false; // 标记消息是否结束

      // 循环读取流数据，直到完成
      while (true) {
        const { done, value } = await reader.read(); // 读取当前块的数据
        if (done) break; // 如果没有更多数据了，停止循环

        const text = decoder.decode(value, { stream: true }); // 解码流数据为文本

        // 检查是否是消息的开始标记
        if (text.includes('data:message_start')) {
          isMessageStarted = true; // 标记消息开始
          accumulatedData = ''; // 清空已累积的数据，重新开始
        }

        // 如果已经开始接收消息，则继续累积数据
        if (isMessageStarted) {
          accumulatedData += text; // 将解码后的文本累积起来

          // 如果遇到消息结束标记，则标记消息结束
          if (text.includes('data:message_end')) {
            isMessageEnded = true;
          }
        }

        // 只有当消息完整接收完毕后，才进行处理
        if (isMessageEnded) {
          // 处理接收到的流数据，去除不必要的标识符
          let filteredData = accumulatedData
            .split('data:') // 按 'data:' 分割字符串
            .filter((item, index) => {
              // 过滤掉第一个 'message_start' 和最后的 'message_end' 标识符
              return !((index === 0 && item === 'message_start') || item === 'message_end');
            })
            .map((item) => item) // 去除两端的空格
            .join('') // 合并有效的数据部分
            .replace(/message_start|message_end/g, ''); // 删除所有标识符

          // 判断并分别处理中文和英文的部分
          let finalData = '';

          // 按字符分割，分别处理中文和英文
          let tempData = '';
          for (let i = 0; i < filteredData.length; i++) {
            const char = filteredData[i];

            // 判断字符是否为英文或中文
            if (/[\u4e00-\u9fa5]/.test(char)) {
              // 中文字符：直接添加并去除空格
              if (tempData.trim() !== '') {
                finalData += tempData.replace(/\s+/g, ''); // 中文部分去空格
                tempData = '';
              }
              finalData += char; // 添加中文字符
            } else if (/[a-zA-Z0-9]/.test(char)) {
              // 英文字符：保留空格
              tempData += char;
            } else {
              // 其他字符（如标点等），根据需求决定是否保留
              tempData += char;
            }
          }

          // 如果 tempData 中有剩余英文内容，添加到最终数据中
          if (tempData.trim() !== '') {
            finalData += tempData;
          }

          // 将处理后的文本赋值给 summaryInfo
          summaryInfo.value = finalData;
          // 查找正在加载的消息
          const loadingIndex = summaryMessages.value.findIndex((message) => message.isLoading);
          if (loadingIndex !== -1) {
            // 处理消息显示，确保 summaryMessages 中的项还存在
            summaryMessages.value[loadingIndex] = { content: '', isUser: false, isLoading: false }; // 替换为没有内容的非加载状态
            nextTick(() => scrollToBottom()); // 滚动到底部，确保显示更新

            // 开始逐字显示 AI 回复的内容
            let charIndex = 0; // 当前显示字符的索引
            const typeEffect = () => {
              // 如果 summaryMessages.value 已经清空或加载的消息已被删除，则停止逐字显示
              if (!summaryMessages.value[loadingIndex] || loadingIndex === -1 || charIndex >= finalData.length) {
                clearInterval(typeInterval); // 完成逐字显示后停止定时器
                return;
              }

              // 逐字显示内容
              summaryMessages.value[loadingIndex].content += finalData.charAt(charIndex); // 逐字显示
              charIndex++; // 更新字符索引
              nextTick(() => scrollToBottom()); // 滚动到底部
            };

            // 使用 setInterval 模拟逐字显示效果
            typeInterval = setInterval(typeEffect, 50); // 每 50ms 显示一个字符
          }

          // 处理完毕后重置标记
          isMessageStarted = false;
          isMessageEnded = false;
          accumulatedData = ''; // 清空累积的数据
        }
      }
    })
    .catch((error) => {
      handleError(); // 发生错误时调用错误处理函数
    });
}, 500);

//文档翻译
const fileTranslate = debounce(async () => {
  let oParam = {
    prompt: fileInfo.value
  };

  // 立即将用户消息和加载中的 AI 消息添加到消息列表
  addUserMessage(null, 'translation');
  inputMsg.value = ''; // 清空输入框

  // 发送请求获取 AI 响应
  await fetch(`${import.meta.env.VITE_APP_BASE_API}/aiqa/personal/chat/documentary/file/translation`, {
    method: 'POST',
    headers: {
      Authorization: 'Bearer ' + getToken(), // 使用 Bearer Token 认证
      'Content-Type': 'application/json', // 请求体为 JSON
      clientid: import.meta.env.VITE_APP_CLIENT_ID // 客户端 ID
    },
    body: JSON.stringify(oParam) // 请求体参数
  } as any)
    .then((response: any) => {
      return response;
    })
    .then(async (response: any) => {
      const reader = response.body.getReader(); // 获取响应的 body 流
      const decoder = new TextDecoder(); // 创建一个解码器，用于将字节流转换为文本
      let accumulatedData = ''; // 用于累积收到的数据
      let isMessageStarted = false; // 标记是否开始接收有效的消息
      let isMessageEnded = false; // 标记消息是否结束

      // 循环读取流数据，直到完成
      while (true) {
        const { done, value } = await reader.read(); // 读取当前块的数据
        if (done) break; // 如果没有更多数据了，停止循环

        const text = decoder.decode(value, { stream: true }); // 解码流数据为文本

        // 检查是否是消息的开始标记
        if (text.includes('data:message_start')) {
          isMessageStarted = true; // 标记消息开始
          accumulatedData = ''; // 清空已累积的数据，重新开始
        }

        // 如果已经开始接收消息，则继续累积数据
        if (isMessageStarted) {
          accumulatedData += text; // 将解码后的文本累积起来

          // 如果遇到消息结束标记，则标记消息结束
          if (text.includes('data:message_end')) {
            isMessageEnded = true;
          }
        }

        // 只有当消息完整接收完毕后，才进行处理
        if (isMessageEnded) {
          // 处理接收到的流数据，去除不必要的标识符
          let filteredData = accumulatedData
            .split('data:') // 按 'data:' 分割字符串
            .filter((item, index) => {
              // 过滤掉第一个 'message_start' 和最后的 'message_end' 标识符
              return !((index === 0 && item === 'message_start') || item === 'message_end');
            })
            .map((item) => item) // 去除两端的空格
            .join('') // 合并有效的数据部分
            .replace(/message_start|message_end/g, ''); // 删除所有标识符

          // 判断并分别处理中文和英文的部分
          let finalData = '';

          // 按字符分割，分别处理中文和英文
          let tempData = '';
          for (let i = 0; i < filteredData.length; i++) {
            const char = filteredData[i];

            // 判断字符是否为英文或中文
            if (/[\u4e00-\u9fa5]/.test(char)) {
              // 中文字符：直接添加并去除空格
              if (tempData.trim() !== '') {
                finalData += tempData.replace(/\s+/g, ''); // 中文部分去空格
                tempData = '';
              }
              finalData += char; // 添加中文字符
            } else if (/[a-zA-Z0-9]/.test(char)) {
              // 英文字符：保留空格
              tempData += char;
            } else {
              // 其他字符（如标点等），根据需求决定是否保留
              tempData += char;
            }
          }

          // 如果 tempData 中有剩余英文内容，添加到最终数据中
          if (tempData.trim() !== '') {
            finalData += tempData;
          }

          // 将处理后的文本赋值给 translationInfo
          translationInfo.value = finalData;
          // 查找正在加载的消息
          const loadingIndex = translationMessages.value.findIndex((message) => message.isLoading);
          if (loadingIndex !== -1) {
            // 处理消息显示，确保 translationMessages 中的项还存在
            translationMessages.value[loadingIndex] = { content: '', isUser: false, isLoading: false }; // 替换为没有内容的非加载状态
            nextTick(() => scrollToBottom()); // 滚动到底部，确保显示更新

            // 开始逐字显示 AI 回复的内容
            let charIndex = 0; // 当前显示字符的索引
            const typeEffect = () => {
              // 如果 translationMessages.value 已经清空或加载的消息已被删除，则停止逐字显示
              if (!translationMessages.value[loadingIndex] || loadingIndex === -1 || charIndex >= finalData.length) {
                clearInterval(typeInterval); // 完成逐字显示后停止定时器
                return;
              }

              // 逐字显示内容
              translationMessages.value[loadingIndex].content += finalData.charAt(charIndex); // 逐字显示
              charIndex++; // 更新字符索引
              nextTick(() => scrollToBottom()); // 滚动到底部
            };

            // 使用 setInterval 模拟逐字显示效果
            typeInterval = setInterval(typeEffect, 50); // 每 50ms 显示一个字符
          }

          // 处理完毕后重置标记
          isMessageStarted = false;
          isMessageEnded = false;
          accumulatedData = ''; // 清空累积的数据
        }
      }
    })
    .catch((error) => {
      handleError(); // 发生错误时调用错误处理函数
    });
}, 500);

// 文档导图(脑图)
const getFilemark = debounce(async () => {
  let oParam = {
    fileName: filedow.value.fileName,
    storageId: markId.value
  };
  if (filedow.value.suffix == 'pdf') {
    mapVla.value = fileInfo.value;
    if (activeInput.value === '4') {
      PreviewmapRefs.value.infoData(mapVla.value);
    }
  } else {
    ApiAImarkDown(oParam).then((res: any) => {
      mapVla.value = res;

      if (activeInput.value === '4') {
        PreviewmapRefs.value.infoData(mapVla.value);
      }
    });
  }
}, 500);

// 开始录音
const startRecordAudio = () => {
  //@ts-ignore
  Recorder?.getPermission().then(
    () => {
      // console.log("开始录音");
      recorder.start(); // 开始录音
      inputMsg.value = '';
      isSpeakType.value = 2;
    },
    (error: any) => {
      proxy.$modal.msgWarning('请先允许该网页使用麦克风');
      // console.log(`${error.name} : ${error.message}`);
    }
  );
};

// 停止录音
const stopRecordAudio = () => {
  recorder.stop();
  var wavBlob = recorder.getWAVBlob();
  isSpeakType.value = 3;
  var formData = new FormData();
  const newbolb = new Blob([wavBlob], { type: 'audio/wav' });
  // //获取当时时间戳作为文件名
  const fileOfBlob = new File([newbolb], new Date().getTime() + '.wav');
  formData.append('file', fileOfBlob);
  axios
    .post('/stt', formData, {
      headers: {
        'Content-Type': 'multipart/form-data'
      }
    })
    .then((res) => {
      console.log(res);
      inputMsg.value = res.data;
      isSpeakType.value = 1;
      textInputRefs.value.focus();
    })
    .catch((err) => {
      isSpeakType.value = 1;
      proxy.$modal.msgError('语音识别失败，请重试');
    });
};

// 计算 输入框 的 width
const inputBotWidth = computed(() => {
  // 直接使用 100vw - 50% 计算宽度
  return `calc(100vw - 50%)`;
});

/*********************************增加部分end */

/*******************************************ai方法start */
const chatMessages = ref(null);
const messages = ref([]) as any;
import useUserStore from '@/store/modules/user';
const userStore = useUserStore();
/**input事件-------------------------start */
// 键盘按下事件--阻止回车换行,执行ctrl + enter换行
const handleKeyPress = (event: any) => {
  // console.log('🚀 ~ handleKeyPress ~ event:', event);
  if (event.keyCode == 13) {
    if (!event.ctrlKey) {
      event.preventDefault();
    } else {
      inputMsg.value += '\n';
    }
  }
};

// 文件大小转换
const formatSize = (size: number) => {
  return proxy.$yuUtils.filterSizeUnit(size);
};

const enterSubmit = (e) => {
  e.preventDefault();
  sendText();
};
// 输入框内容变化时触发
const sendTextInput = (e) => {
  if (e.trim() !== '') {
    showHight.value = true;
  }
};

/**input事件-------------------------end */

// 移除文件
const forkRemove = (file) => {
  // 调用 `ElMessageBox` 弹出确认框
  ElMessageBox.confirm(`确定移除 ${file.name} ?`, '确认移除', {
    confirmButtonText: '确认',
    cancelButtonText: '取消',
    type: 'warning'
  })
    .then(() => {
      // 这里调用 `handleRemove` 来移除文件
      const index = Listfile.value.findIndex((f) => f.name === file.name);
      if (index !== -1) {
        Listfile.value.splice(index, 1); // 移除文件
        onlineSrc.value = '';
        headerStyle.value.width = '0px';
      }
      // console.log('🚀 ~ forkRemo ~ file removed:', file);
    })
    .catch(() => {
      // console.log('🚀 ~ forkRemo ~ file removal cancelled:', file);
    });
};

const TranslateInfo = ref('');

let typeInterval; // 在外部定义 typeInterval，方便控制停止
//拿到AI响应回来的接口数据
const handleApiResponse00 = async (response) => {
  const reader = response.body.getReader(); // 获取响应的 body 流
  const decoder = new TextDecoder(); // 创建一个解码器，用于将字节流转换为文本
  let accumulatedData = ''; // 用于累积收到的数据
  let isMessageStarted = false; // 标记是否开始接收有效的消息
  let isMessageEnded = false; // 标记消息是否结束

  // 循环读取流数据，直到完成
  while (true) {
    try {
      const { done, value } = await reader.read(); // 读取当前块的数据
      if (done) {
        msgLoading.value = false;
        // // 结束时处理已接收到的数据
        // if (accumulatedData.trim() !== '') {
        //   await processData(accumulatedData); // 处理收到的完整数据
        // }
        // break; // 如果没有更多数据了，停止循环
      }
      let accumulatedContent = ''; // 用于累积所有content内容
      const text = decoder.decode(value); // 利用解码器把数据解析成字符串
      const chunk = handleChunkData(text); // 处理切片数据
      // 判断是否有不完整切片，如果有，合并下一次处理，没有则获取数据
      if (chunkRef.value) continue;

      let decodedArray = chunk.split('data:');
      // 处理每条消息

      for (const msg of decodedArray) {
        try {
          const parsed = JSON.parse(msg);
          if (parsed.message?.content) {
            accumulatedContent += parsed.message.content;

            // 如果是最后一条消息(done为true)
            if (parsed.done === true) {
              // 处理完整的累积内容
              await processData(accumulatedContent);
              // 重置累积内容
              accumulatedContent = '';
            }
          }
        } catch (e) {
          console.error('Error parsing message:', e);
          continue;
        }
      }

      console.log('🚀 ~ handleApiResponse ~ decodedArray:', accumulatedContent);
      return;
      // 检查是否是消息的开始标记
      if (text.includes('data:message_start')) {
        isMessageStarted = true; // 标记消息开始
        accumulatedData = ''; // 清空已累积的数据，重新开始
      }

      // 如果已经开始接收消息，则继续累积数据
      if (isMessageStarted) {
        accumulatedData += text; // 将解码后的文本累积起来

        // 如果遇到消息结束标记，则标记消息结束
        if (text.includes('data:message_end')) {
          isMessageEnded = true;
        }
      }

      // 只有当消息完整接收完毕后，才进行处理
      if (isMessageEnded) {
        await processData(accumulatedData); // 处理接收到的流数据
        // 重置标记，准备接收下一条消息
        isMessageStarted = false;
        isMessageEnded = false;
        accumulatedData = ''; // 清空累积的数据
      }
    } catch (error) {
      console.error('Error reading the stream:', error);
      handleError(); // 发生错误时调用错误处理函数
      break;
    }
  }
};

const handleApiResponse = async (response) => {
  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  let accumulatedContent = ''; // 用于累积所有content内容

  while (true) {
    try {
      const { done, value } = await reader.read();
      if (done) {
        isStart.value = false;
        break;
      }

      const text = decoder.decode(value);
      const chunk = handleChunkData(text);
      if (chunkRef.value) continue;

      // 将数据按data:分割并过滤空值
      const messages = chunk
        .split('data:')
        .filter((msg) => msg.trim())
        .map((msg) => msg.trim());

      // 处理每条消息
      for (const msg of messages) {
        try {
          // 检查消息格式是否完整
          if (!msg.endsWith('}')) {
            continue; // 跳过不完整的JSON
          }

          // 尝试解析JSON
          let parsed;
          try {
            parsed = JSON.parse(msg);
          } catch (e) {
            // console.warn('Invalid JSON message:', msg);
            continue;
          }

          // 确保消息包含必要的字段
          if (parsed && parsed.message && typeof parsed.message.content === 'string') {
            accumulatedContent += parsed.message.content;

            // 如果是最后一条消息(done为true)
            if (parsed.done == true) {
              // 处理完整的累积内容
              await processData(accumulatedContent);
              // 重置累积内容
              accumulatedContent = '';
            }
          }
        } catch (e) {
          // console.warn('Error processing message:', e);
          continue;
        }
      }
      console.log('🚀 ~ handleApiResponse ~ accumulatedContent:', accumulatedContent);
    } catch (error) {
      handleError();
      break;
    }
  }
};

// 处理数据并回显 AI 的内容
const processData = async (data) => {
  // 查找正在加载的消息
  const loadingIndex = messages.value.findIndex((message) => message.isLoading);
  if (loadingIndex !== -1) {
    // 处理消息显示，确保 messages 中的项还存在
    messages.value[loadingIndex] = { content: '', isUser: false, isLoading: false }; // 替换为没有内容的非加载状态
    nextTick(() => scrollToBottom()); // 滚动到底部，确保显示更新

    // 检查是否为 Markdown 代码块，如果是则提取内容
    const markdownCodeBlock = /^```markdown\n([\s\S]*?)\n```$/;
    const match = data.match(markdownCodeBlock);
    if (match) {
      data = match[1]; // 提取代码块内的内容
    }

    // 开始逐字显示 AI 回复的内容
    let charIndex = 0; // 当前显示字符的索引
    const typeEffect = () => {
      // 如果 messages.value 已经清空或加载的消息已被删除，则停止逐字显示
      if (!messages.value[loadingIndex] || loadingIndex === -1 || charIndex >= data.length) {
        clearInterval(typeInterval); // 完成逐字显示后停止定时器

        // 调用历史记录接口
        // nextTick(() => saveHistory());

        isStart.value = false; // 回复显示完毕，设置为 false
        return;
      }

      // 逐字显示内容
      messages.value[loadingIndex].content += data.charAt(charIndex); // 逐字显示
      charIndex++; // 更新字符索引
      nextTick(() => scrollToBottom()); // 滚动到底部
    };

    // 使用 setInterval 模拟逐字显示效果
    typeInterval = setInterval(typeEffect, 50); // 每 50ms 显示一个字符
  }
};

const processData0 = async (data) => {
  // 查找正在加载的消息
  const loadingIndex = messages.value.findIndex((message) => message.isLoading);
  if (loadingIndex !== -1) {
    // 处理消息显示，确保 messages 中的项还存在
    messages.value[loadingIndex] = { content: '', isUser: false, isLoading: false }; // 替换为没有内容的非加载状态
    nextTick(() => scrollToBottom()); // 滚动到底部，确保显示更新

    // 检查是否以 "```markdown" 开头，如果是则去掉
    const markdownCodeBlock = /^```markdown\n([\s\S]*?)\n```$/;

    const markdownPrefix = '```markdown';
    if (data.startsWith(markdownPrefix)) {
      data = data.slice(markdownPrefix.length);
    }

    // 开始逐字显示 AI 回复的内容
    let charIndex = 0; // 当前显示字符的索引
    const typeEffect = () => {
      // 如果 messages.value 已经清空或加载的消息已被删除，则停止逐字显示
      if (!messages.value[loadingIndex] || loadingIndex === -1 || charIndex >= data.length) {
        clearInterval(typeInterval); // 完成逐字显示后停止定时器

        // 调用历史记录接口
        // nextTick(() => saveHistory());

        isStart.value = false; // 回复显示完毕，设置为 false
        return;
      }

      // 逐字显示内容
      messages.value[loadingIndex].content += data.charAt(charIndex); // 逐字显示
      charIndex++; // 更新字符索引
      nextTick(() => scrollToBottom()); // 滚动到底部
    };

    // 使用 setInterval 模拟逐字显示效果
    typeInterval = setInterval(typeEffect, 50); // 每 50ms 显示一个字符
  }
};

//处理数据并回显AI的内容
const processData00 = async (data) => {
  // 查找正在加载的消息
  const loadingIndex = messages.value.findIndex((message) => message.isLoading);
  if (loadingIndex !== -1) {
    // 处理消息显示，确保 messages 中的项还存在
    messages.value[loadingIndex] = { content: '', isUser: false, isLoading: false }; // 替换为没有内容的非加载状态
    nextTick(() => scrollToBottom()); // 滚动到底部，确保显示更新

    // 开始逐字显示 AI 回复的内容
    let charIndex = 0; // 当前显示字符的索引
    const typeEffect = () => {
      // 如果 messages.value 已经清空或加载的消息已被删除，则停止逐字显示
      if (!messages.value[loadingIndex] || loadingIndex === -1 || charIndex >= data.length) {
        clearInterval(typeInterval); // 完成逐字显示后停止定时器

        // 调用历史记录接口
        // nextTick(() => saveHistory());

        isStart.value = false; // 回复显示完毕，设置为 false
        return;
      }

      // 逐字显示内容
      messages.value[loadingIndex].content += data.charAt(charIndex); // 逐字显示
      charIndex++; // 更新字符索引
      nextTick(() => scrollToBottom()); // 滚动到底部
    };

    // 使用 setInterval 模拟逐字显示效果
    typeInterval = setInterval(typeEffect, 50); // 每 50ms 显示一个字符
  }

  // if (loadingIndex !== -1) {
  //   // 处理消息显示，确保 messages 中的项还存在
  //   messages.value[loadingIndex] = { content: '', isUser: false, isLoading: false }; // 替换为没有内容的非加载状态
  //   nextTick(() => scrollToBottom()); // 滚动到底部，确保显示更新
  // }
  // isStart.value = false; // 回复显示完毕，设置为 false
  // messages.value[loadingIndex].content += data;

  return;
  try {
    if (!isQa.value) {
      // 处理接收到的流数据，去除不必要的标识符
      let filteredData = data
        .split('data:') // 按 'data:' 分割字符串
        .filter((item, index) => {
          // 过滤掉第一个 'message_start' 和最后的 'message_end' 标识符
          return !((index === 0 && item === 'message_start') || item === 'message_end');
        })
        .map((item) => item) // 去除两端的空格
        .join('') // 合并有效的数据部分
        .replace(/message_start|message_end/g, ''); // 删除所有标识符

      // 判断并分别处理中文和英文的部分
      let finalData = '';

      // 按字符分割，分别处理中文和英文
      let tempData = '';
      for (let i = 0; i < filteredData.length; i++) {
        const char = filteredData[i];

        // 判断字符是否为英文或中文
        if (/[\u4e00-\u9fa5]/.test(char)) {
          // 中文字符：直接添加并去除空格
          if (tempData.trim() !== '') {
            finalData += tempData.replace(/\s+/g, ''); // 中文部分去空格
            tempData = '';
          }
          finalData += char; // 添加中文字符
        } else if (/[a-zA-Z0-9]/.test(char)) {
          // 英文字符：保留空格
          tempData += char;
        } else {
          // 其他字符（如标点等），根据需求决定是否保留
          tempData += char;
        }
      }

      // 如果 tempData 中有剩余英文内容，添加到最终数据中
      if (tempData.trim() !== '') {
        finalData += tempData;
      }

      // 将处理后的文本赋值给 TranslateInfo
      TranslateInfo.value = finalData;

      // 查找正在加载的消息
      const loadingIndex = messages.value.findIndex((message) => message.isLoading);

      if (loadingIndex !== -1) {
        // 处理消息显示，确保 messages 中的项还存在
        messages.value[loadingIndex] = { content: '', isUser: false, isLoading: false }; // 替换为没有内容的非加载状态
        nextTick(() => scrollToBottom()); // 滚动到底部，确保显示更新

        // 开始逐字显示 AI 回复的内容
        let charIndex = 0; // 当前显示字符的索引
        const typeEffect = () => {
          // 如果 messages.value 已经清空或加载的消息已被删除，则停止逐字显示
          if (!messages.value[loadingIndex] || loadingIndex === -1 || charIndex >= finalData.length) {
            clearInterval(typeInterval); // 完成逐字显示后停止定时器

            // 调用历史记录接口
            nextTick(() => saveHistory());

            isStart.value = false; // 回复显示完毕，设置为 false
            return;
          }

          // 逐字显示内容
          messages.value[loadingIndex].content += finalData.charAt(charIndex); // 逐字显示
          charIndex++; // 更新字符索引
          nextTick(() => scrollToBottom()); // 滚动到底部
        };

        // 使用 setInterval 模拟逐字显示效果
        typeInterval = setInterval(typeEffect, 50); // 每 50ms 显示一个字符
      }
    } else {
      // 处理接收到的流数据，去除不必要的标识符
      let filteredData = data
        .split('data:') // 按 'data:' 分割字符串
        .filter((item, index) => {
          // 过滤掉第一个 'message_start' 和最后的 'message_end' 标识符
          return !((index === 0 && item === 'message_start') || item === 'message_end');
        })
        .map((item) => item) // 去除两端的空格
        .join('') // 合并有效的数据部分
        .replace(/message_start|message_end/g, ''); // 删除所有标识符

      // 判断并分别处理中文和英文的部分
      let finalData = '';

      // 按字符分割，分别处理中文和英文
      let tempData = '';
      for (let i = 0; i < filteredData.length; i++) {
        const char = filteredData[i];

        // 判断字符是否为英文或中文
        if (/[\u4e00-\u9fa5]/.test(char)) {
          // 中文字符：直接添加并去除空格
          if (tempData.trim() !== '') {
            finalData += tempData.replace(/\s+/g, ''); // 中文部分去空格
            tempData = '';
          }
          finalData += char; // 添加中文字符
        } else if (/[a-zA-Z0-9]/.test(char)) {
          // 英文字符：保留空格
          tempData += char;
        } else {
          // 其他字符（如标点等），根据需求决定是否保留
          tempData += char;
        }
      }

      // 如果 tempData 中有剩余英文内容，添加到最终数据中
      if (tempData.trim() !== '') {
        finalData += tempData;
      }

      // 将处理后的文本赋值给 TranslateInfo
      TranslateInfo.value = finalData;

      // 查找正在加载的消息
      const loadingIndex = msgFile.value.findIndex((msgFile) => msgFile.isLoading);

      if (loadingIndex !== -1) {
        // 处理消息显示，确保 messages 中的项还存在
        msgFile.value[loadingIndex] = { content: '', isUser: false, isLoading: false }; // 替换为没有内容的非加载状态
        nextTick(() => scrollToBottom()); // 滚动到底部，确保显示更新

        // 开始逐字显示 AI 回复的内容
        let charIndex = 0; // 当前显示字符的索引
        const typeEffect = () => {
          // 如果 messages.value 已经清空或加载的消息已被删除，则停止逐字显示
          if (!msgFile.value[loadingIndex] || loadingIndex === -1 || charIndex >= finalData.length) {
            clearInterval(typeInterval); // 完成逐字显示后停止定时器

            // 调用历史记录接口
            nextTick(() => saveHistory());

            isStart.value = false; // 回复显示完毕，设置为 false
            return;
          }

          // 逐字显示内容
          msgFile.value[loadingIndex].content += finalData.charAt(charIndex); // 逐字显示
          charIndex++; // 更新字符索引
          nextTick(() => scrollToBottom()); // 滚动到底部
        };

        // 使用 setInterval 模拟逐字显示效果
        typeInterval = setInterval(typeEffect, 50); // 每 50ms 显示一个字符
      }
    }
  } catch (error) {
    // console.error('Error processing data:', error);
    handleError(); // 处理异常
  }
};

// 停止回答
const stopTextClick = () => {
  controller.value.abort();
  controller.value = new AbortController();
};

// 播放音频---item.isAudio(播放:play 暂停:pause)
const playAudioClick = (item: any) => {
  if ('speechSynthesis' in window) {
    messages.value.forEach((v: any) => {
      v.isAudio = 'play';
      pauseAudioClick(v);
    });
    const utterance = new SpeechSynthesisUtterance(item.content);
    utterance.lang = 'zh-CN'; // 设置语言为中文
    utterance.rate = 1; // 设置语速为0.8倍（正常语速）
    utterance.pitch = 1; // 设置音调为1（正常音调）
    utterance.volume = 1; // 设置音量（1为最大音量）

    // 监听语音播放结束事件
    utterance.onend = () => {
      // 在这里可以添加其他逻辑，比如更新UI状态等
      item.isAudio = 'play'; // 恢复播放图标
    };
    speechSynthesis.speak(utterance);
    item.isAudio = 'pause';
  } else {
    proxy.$modal.msgWarning('当前浏览器不支持语音合成功能!');
  }
};

// 暂停音频
const pauseAudioClick = (item?: any) => {
  speechSynthesis?.cancel();
  if (item) {
    item.isAudio = 'play'; // 恢复播放图标
  }
};

// 重新回答
const reanswerClick = (item, index) => {
  // 先确保index合法
  if (index > 0 && index <= messages.value.length) {
    const message = messages.value[index - 1];
    if (message && message.content) {
      inputMsg.value = message.content;
      sendText();
    }
  }
};
// const reanswerClick = (item, index) => {
//   inputMsg.value = messages.value[index - 1].message;
//   sendText();
// };

//复制
const copyClick = async (textToCopy: any) => {
  try {
    // await navigator.clipboard.writeText(textToCopy);
    if (proxy?.$yuUtils.YUcopyToClipboard(textToCopy)) {
      proxy?.$modal.msgSuccess('已复制到剪贴板!');
    } else {
      proxy.$modal.msgError('复制失败!');
    }
  } catch (err) {
    proxy.$modal.msgError('复制失败!');
    console.log(err);
  }
};

// 发送消息(自定义axios发送)
const sendText = async () => {
  if (isStart.value) {
    proxy?.$modal.msgWarning(proxy.$t('AI正在回复中，请稍后...'));
    return;
  }
  if (!isQa.value) {
    // 普通聊天模式
    if (inputMsg.value.trim() === '') {
      // 如果用户输入为空，弹出警告
      proxy?.$modal.msgWarning(proxy.$t('chatGpt.chatMsg1'));
      return;
    }

    // 整理历史消息，去除正在加载的消息
    const history = messages.value
      .filter((message) => !message.isLoading)
      .map((message) => ({ role: message.isUser ? 'user' : 'assistant', content: message.content }));

    // 构建请求参数
    const oParam = {
      prompt: fileInfo.value,
      content: inputMsg.value,
      history: JSON.stringify(history) || null
    };

    // 立即将用户消息和加载中的 AI 消息添加到消息列表
    MessageaddUser(inputMsg.value);
    inputMsg.value = ''; // 清空输入框
    isStart.value = true;

    try {
      // 发送请求获取 AI 响应
      const response = await fetch(`${import.meta.env.VITE_APP_BASE_API}/aiqa/personal/chat/documentary/qa`, {
        method: 'POST',
        signal: controller.value.signal, //停止请求
        headers: {
          Authorization: 'Bearer ' + getToken(), // 使用 Bearer Token 认证
          'Content-Type': 'application/json', // 请求体为 JSON
          clientid: import.meta.env.VITE_APP_CLIENT_ID // 客户端 ID
        },
        body: JSON.stringify(oParam) // 请求体参数
      });
      // 处理 API 响应
      await handleApiResponse(response);
    } catch (error) {
      handleError(); // 发生错误时调用错误处理函数
    }
  } else {
    // 文件上传聊天模式
    if (inputMsg.value.trim() === '') {
      // 如果消息为空且文件未上传，弹出警告
      proxy?.$modal.msgWarning(proxy.$t('chatGpt.chatMsg1'));
      return;
    } else if (Listfile.value.length === 0) {
      // 如果选择了文件上传模式，但未选择文件，弹出提示    msgFile;
      ElMessage.warning('请选择上传文件');
      return;
    }

    // 整理历史消息，去除正在加载的消息
    const history = messages.value
      .filter((messages) => !messages.isLoading)
      .map((messages) => ({ role: messages.isUser ? 'user' : 'assistant', content: messages.content }));
    let oParam = {
      prompt: fileInfo.value,
      content: inputMsg.value,
      history: JSON.stringify(history) || null // 将历史消息转换为 JSON 字符串并添加到 oParam
    };

    // 立即将用户消息和加载中的 AI 消息添加到消息列表
    MessageFile(inputMsg.value);
    inputMsg.value = ''; // 清空输入框
    isStart.value = true;
    try {
      // 发送文件上传请求
      const response = await fetch(`${import.meta.env.VITE_APP_BASE_API}/aiqa/personal/chat/documentary/qa`, {
        method: 'POST',
        signal: controller.value.signal, //停止请求
        headers: {
          Authorization: 'Bearer ' + getToken(), // 使用 Bearer Token 认证
          'Content-Type': 'application/json', // 请求体为 JSON
          clientid: import.meta.env.VITE_APP_CLIENT_ID // 客户端 ID
        },
        body: JSON.stringify(oParam) // 请求体参数
        // body: formData // 请求体为 FormData
      });
      // 处理 API 响应
      await handleApiResponse(response);
    } catch (error) {
      handleError(); // 发生错误时调用错误处理函数
    }
  }
};

// 加载中的 AI 消息到消息列表(总结和翻译调用的显示消息方法)
const addUserMessage = (messageContent = '', type) => {
  if (type == 'summary') {
    if (messageContent) {
      summaryMessages.value.push({
        content: messageContent, // 添加用户消息内容
        isUser: true // 标记为用户消息
      });
      nextTick(() => scrollToBottom()); // 滚动到底部
    }

    summaryMessages.value.push({
      content: '...', // 初始 loading 消息
      isUser: false, // 标记为 AI 消息
      isLoading: true // 设置为加载状态
    });

    nextTick(() => scrollToBottom()); // 滚动到底部
  } else if (type == 'translation') {
    if (messageContent) {
      translationMessages.value.push({
        content: messageContent, // 添加用户消息内容
        isUser: true // 标记为用户消息
      });
      nextTick(() => scrollToBottom()); // 滚动到底部
    }

    translationMessages.value.push({
      content: '...', // 初始 loading 消息
      isUser: false, // 标记为 AI 消息
      isLoading: true // 设置为加载状态
    });

    nextTick(() => scrollToBottom()); // 滚动到底部
  } else if (type == 'Extract') {
    if (messageContent) {
      extractMsg.value.push({
        content: messageContent, // 添加用户消息内容
        isUser: true // 标记为用户消息
      });
      nextTick(() => scrollToBottom()); // 滚动到底部
    }

    extractMsg.value.push({
      content: '...', // 初始 loading 消息
      isUser: false, // 标记为 AI 消息
      isLoading: true // 设置为加载状态
    });

    nextTick(() => scrollToBottom()); // 滚动到底部
  }
};

// 添加用户消息和加载中的 AI 消息到消息列表(AI问答调用的消息显示方法)
const MessageaddUser = (messageContent, isHistory = false) => {
  if (messageContent) {
    messages.value.push({
      content: messageContent, // 添加用户消息内容
      isUser: true // 标记为用户消息
    });
    nextTick(() => scrollToBottom()); // 滚动到底部

    // 如果不是历史记录回显，添加一个加载中的 AI 消息
    if (!isHistory) {
      messages.value.push({
        content: '', // 初始 loading 消息
        isUser: false, // 标记为 AI 消息
        isLoading: true // 设置为加载状态
      });
      nextTick(() => scrollToBottom()); // 滚动到底部
    }
  }
};

const MessageFile = (messageContent, isHistory = false) => {
  if (messageContent) {
    msgFile.value.push({
      content: messageContent, // 添加用户消息内容
      isUser: true // 标记为用户消息
    });
    nextTick(() => scrollToBottom()); // 滚动到底部

    // 如果不是历史记录回显，添加一个加载中的 AI 消息
    if (!isHistory) {
      msgFile.value.push({
        content: '...', // 初始 loading 消息
        isUser: false, // 标记为 AI 消息
        isLoading: true // 设置为加载状态
      });
      nextTick(() => scrollToBottom()); // 滚动到底部
    }
  }
};

// 错误处理函数
const handleError = () => {
  // 查找正在加载的消息
  const loadingIndex = messages.value.findIndex((message) => message.isLoading);
  isStart.value = false;
  if (loadingIndex !== -1) {
    // 替换为错误提示消息
    messages.value[loadingIndex] = {
      content: '发生错误，请稍后再试。',
      isUser: false,
      isLoading: false // 标记为非加载状态
    };

    nextTick(() => scrollToBottom()); // 滚动到底部
  }

  ElMessage.error('发生错误，请稍后重试。'); // 弹出错误提示
};

// 滚动到底部
const scrollToBottom = () => {
  if (chatMessages.value) {
    const chatMag = chatMessages.value;
    chatMag.scrollTop = chatMag.scrollHeight;
  }
};

// 流式数据会有被截断的情况，需要做一些容错处理
const chunkRef = ref();
const handleChunkData = (chunk: string) => {
  chunk = chunk.trim();
  // 如果存在上一个切片
  if (chunkRef.value) {
    chunk = chunkRef.value + chunk;
    chunkRef.value = '';
  }

  // 如果存在done,认为是完整切片且是最后一个切片
  if (chunk.includes('[DONE]')) {
    return chunk;
  }

  // 最后一个字符串不为}，则默认切片不完整，保存与下次拼接使用（这种方法不严谨，但已经能解决大部分场景的问题）
  if (chunk[chunk.length - 1] !== '}') {
    chunkRef.value = chunk;
  }
  return chunk;
};
/*******************************************ai方法end */

/*****************************文件上传 start */
const Listfile = ref([]);
const filedow = ref('') as any;

//判断是否显示AI问答页面
const updateShowHight = () => {
  if (Listfile.value.length > 0 || inputMsg.value.trim() !== '' || messages.value.length > 0) {
    showHight.value = true;
  }
};

const handleRemove = (file, fileList) => {
  Listfile.value = fileList; // 更新文件列表
  updateShowHight(); // 更新 showHight 状态

  // console.log(file, fileList);
};

watch(
  () => Listfile.value,
  (newValue) => {
    updateShowHight(); // 在 watch 中直接更新 showHight
  },
  { deep: true, immediate: true }
);

const files = ref('');
// 获取文件列表信息
const handlePreview = (file, fileList) => {
  files.value = file.raw;
  // 提取文件扩展名
  const suffix = file.name.split('.').pop() || '';
  const fileName = file.name.split('.')[0];

  // 判断文件类型，根据扩展名确定
  const validTypes = ['ppt', 'pptx', 'excel', 'docx', 'doc', 'xlsx', 'xls'];
  const type = validTypes.includes(suffix.toLowerCase()) ? 'file' : '';

  Listfile.value = fileList;

  // 添加新的属性到 filedow.value
  filedow.value = {
    ...file,
    type, // 添加type属性
    suffix, // 添加suffix属性
    fileName //截取后的文件名
  };

  if (Listfile.value.length > 0) {
    checkData();
  }
};

const handleExceed = (files, fileList) => {
  ElMessage.warning(`当前限制选择 1 个文件，本次选择了 ${files.length} 个文件，共选择了 ${files.length + fileList.length} 个文件`);
};

import type { UploadProps } from 'element-plus';
import { isStarted } from 'nprogress';

const beforeRemove: UploadProps['beforeRemove'] = (uploadFile) => {
  // 使用ElMessageBox.confirm来确认是否移除文件
  return ElMessageBox.confirm(`确定移除 ${uploadFile.name} ?`, '确认移除', {
    confirmButtonText: '确认',
    cancelButtonText: '取消',
    type: 'warning'
  })
    .then(() => {
      // 每次文件移除后更新 key，强制触发渲染和过渡
      return true; // 移除文件
    })
    .catch(() => {
      return false; // 不移除文件
    });
};

//上传之前执行的函数
const beforeUpload = (file) => {
  //MIME：文件类型的描述
  // let mime = ["image/jpeg", "image/png", "image/gif", "image/webp"]; //允许上传三种格式的图片
  // const isJPG = mime.includes(file.type);
  // const isLt2M = file.size / 1024 / 1024 < 2;

  // if (!isJPG) {
  //   this.$message.error("上传头像图片只能是 JPG、PNG、GIF、webp 格式!");
  // }
  // if (!isLt2M) {
  //   this.$message.error("上传头像图片大小不能超过 2MB!");
  // }
  // return isJPG && isLt2M;

  const maxSize = 30 * 1024 * 1024; // 50MB
  const isLt30M = file.size < maxSize;

  if (!isLt30M) {
    ElMessage.error('上传文件大小不能超过 30MB!');
  }
  return isLt30M;
};

// 验证数据是否正确
const checkData = () => {
  let oParam = {
    fileSize: Listfile.value[0].size,
    fileName: filedow.value.fileName,
    fileSuffix: Listfile.value[0].name.split('.').pop() || '',
    type: 'qa'
  };

  ApiTempverifyData(oParam).then((res) => {
    if (res.code == 200) {
      Upconfirm();
    } else {
      return false;
    }
  });
};

// 确认上传
const Upconfirm = async () => {
  let formdata = new FormData();
  formdata.append('file', files.value);
  formdata.append('fileName', filedow.value.fileName);
  formdata.append('type', 'qa');

  ApiTempOrdinary(formdata).then((res) => {
    if (res.code == 200) {
      analysisFlie();
    } else {
      ElMessage.error(res.msg);
    }
    // console.log(res, "000000000");
  });
};

const fileInfo = ref('') as any;

// 解析文件内容
const analysisFlie = async () => {
  Isloading.value = true;
  let formdata = new FormData();
  formdata.append('file', files.value);
  formdata.append('fileName', filedow.value.fileName);
  ApiAIfileChat(formdata).then((res) => {
    Isloading.value = false;
    fileInfo.value = res.data.prompt;
    markId.value = res.data.fileId;
    if (Listfile.value.length > 0) {
      isChat.value = true;
    }
    getFileDataInfo(res.data.fileId);
  });
};

// 获取文件并渲染到页面
// const getFileDataInfo = (id: string) => {
//   let oParam = {
//     moduleId: id, //文件id
//     // previewType: 'onlyOffice',
//     versionId: null, //文件版本
//     type: 'qa' //类型 不同模块库编码
//   };
//   onlinePreviewApi.getFileDataInfo(oParam).then((res: any) => {
//     // onlineSrc.value = 'http://' + res.data.url
//     onlineSrc.value = res.data.url;
//     headerStyle.value.width = '45%';
//     Styleheader.value.height = 'calc(95vh - 10px)';
//     inputStyle.value.height = 'calc(95vh - 15px)';
//   });
// };
const fileDetail: any = ref({});
const getFileDataInfo = (id: string) => {
  let params = {
    moduleId: id, //文件id
    versionId: null, //文件版本
    type: 'qa', //类型 不同模块库编码
    previewType: 'onlyOffice'
  };
  onlinePreviewApi.getFileDataInfo(params).then((res: any) => {
    if (res.code == '200') {
      onlineSrc.value = res.data.url;
      fileDetail.value = res.data;
      fileDetail.value.versionNameValue = proxy.$moment(fileDetail.versionName).format('YYYY-MM-DD HH:mm:ss');
      watermarkTxt.value = res.data.watermarkTxt;
      headerStyle.value.width = '50%';
      Styleheader.value.height = 'calc(95vh - 10px)';
      // inputStyle.value.height = 'calc(95vh - 15px)';
      inputStyle.value.height = 'calc(99vh - 84px)';
      const s = document.createElement('script');
      s.type = 'text/javascript';
      // s.src = 'http://' + res.data.previewServer + "/web-apps/apps/api/documents/api.js";
      s.src = res.data.previewServer + '/web-apps/apps/api/documents/api.js';
      document.body.appendChild(s);

      setTimeout(() => {
        var config = {
          document: {
            fileType: fileDetail.value.fileSuffix.replace('.', ''),
            key: route.query.onlineType + fileDetail.id + route.query.versionId ? route.query.versionId : fileDetail.versionId,
            title: ' ',
            url: onlineSrc.value,
            permissions: {
              download: false,
              print: false,
              modifyFilter: false
            }
          },
          // permissions: {
          //   print: false,
          //   download: false,
          //   modifyFilter: false
          // },
          documentType: fileDetail.documentType,
          editorConfig: {
            lang: 'zh-CN',
            mode: 'view',
            callbackUrl: '',
            customization: {
              logo: {
                image: 'logoUrl',
                imageDark: 'logoUrl',
                url: window.location.origin
              },
              customer: {
                address: '',
                info: '',
                logo: 'logoUrl',
                logoDark: 'logoUrl',
                mail: 'sales@cdeden.cn',
                name: '成都伊登软件有限公司',
                phone: '028-85230818',
                www: 'http://cdeden.cn/'
              },
              help: false
            },
            user: {
              id: userStore.userId,
              name: `${userStore.nickname}(${userStore.userId})`
              // name: `admin123`
            }
          }
        };
        //@ts-ignore
        var docEditor: any = new DocsAPI.DocEditor('placeholder', config);

        // nextTick(() => {
        //      this.$store.state.user.coverLogoDiv = true;
        //   });
      }, 1000);
    }
  });
};

// 判断文件加载完成
const onLoaded = (pdfApp) => {
  // console.log('文件加载完成', pdfApp);
  Pdfloading.value = false;
};

/*****************************文件上传 end */

// 切换选中的 tab
const clear = () => {
  Listfile.value = [];
  inputMsg.value = '';
  messages.value = [];
};

const toggleListfile = () => {
  Listfile.value = Listfile.value.length > 0 ? [] : ['file1', 'file2'];
  // 每次更新 Listfile 后，强制触发渲染并更新 key
};
const toggleInputMsg = () => {
  inputMsg.value = inputMsg.value !== '' ? '' : ' ';
};

const beforeEnter = (el) => {
  el.style.height = '0'; // 初始高度为 0
  el.style.transition = 'height 0.5s ease-in-out'; // 设置过渡
};

const enter = (el, done) => {
  el.offsetHeight; // 强制触发重新计算
  // el.style.height = 'calc(100vh - 365px)'; // 过渡到目标高度
  el.style.height = 'calc(100vh - 100px)'; // 过渡到目标高度
  done(); // 完成过渡
};

const leave = (el, done) => {
  el.style.height = '0'; // 离开时高度恢复为 0
  done(); // 完成过渡
};

//icon图标
const selectSvgIcons = (v: any) => {
  return proxy.$yuUtils.selectSvgIcon(v);
};

defineExpose({
  //调用组件需要导出 v-model的变量
  clear
});
</script>

<style>
.el-popper.is-customized {
  /* Set padding to ensure the height is 32px */
  padding: 6px 12px;
  /* background-image: linear-gradient(90deg, #4facfe 0%, #00f2fe 100%); */
  background-image: linear-gradient(90deg, #6a11cb 0%, #2575fc 100%);
  color: #fff;
}

.el-popper.is-customized .el-popper__arrow::before {
  background-image: linear-gradient(90deg, #6a11cb 0%, #2575fc 100%);
  right: 0;
  color: #fff;
}

.md-editor-preview-wrapper {
  position: relative;
  flex: 1;
  box-sizing: border-box;
  overflow: auto;
  padding: 0px 0px !important;
}

/* .language-markdown {
  background-color: #fff;
} */
</style>

<style scoped lang="scss">
:deep(.Dropdown_item_menu) {
  padding-top: 5px !important;
  padding-bottom: 5px !important;
  font-size: 14px !important;

  &:hover {
    background-color: #f5f5f5 !important;
    color: #606266;
  }
}

:deep(.Dropdown_item_menu_more) {
  padding-top: 5px !important;
  padding-bottom: 5px !important;
  font-size: 14px !important;
  box-sizing: border-box;
  position: relative !important;

  .info {
    display: none;
  }

  &:hover {
    .info {
      display: block;
      position: absolute !important;
      left: 120px;
      top: -50%;
      width: 100px;
      height: 100px;
      background-color: white;
      padding: 10px 0px;
      p {
        margin: 0;
        padding: 0;
        text-align: center;
        line-height: 35px;

        &:hover {
          background-color: #f5f5f5 !important;
          color: #606266;
        }
      }
    }
    background-color: #f5f5f5 !important;
    color: #606266;
  }
}

:deep(.border_bottom) {
  border-bottom: 1px solid #dcdfe6 !important;
}

.personalization {
  display: flex;
  justify-content: space-between;
  align-items: center;
  color: #606266 !important;
}

.show_box:hover {
  .list_foot {
    // display: block !important;
    visibility: visible !important;
  }
}

// .last_foot_visible {
//   visibility: visible !important;
// }

.list_foot {
  display: flex;
  visibility: hidden;
  // display: none;
  padding: 0px 0 8px;
  margin-top: 6px;

  .div_icon {
    background-color: #ffffff;
    box-shadow:
      rgba(16, 24, 40, 0.1) 0px 4px 8px -2px,
      rgba(16, 24, 40, 0.06) 0px 2px 4px -2px;
    border-radius: 6px;
    padding: 7px 6px 3px;
    margin-right: 5px;
    color: #667085;
    cursor: pointer;

    &:hover {
      color: #f08f00;
    }
  }

  .div_icon_volume {
    padding: 6px 6px 4px;
  }

  .reanswer_btn {
    font-size: 12px;
    color: #8789ad;
    font-weight: 500;
    cursor: pointer;
    display: flex;
    align-items: center;

    img {
      margin-right: 5px;
    }
  }

  .copy {
    cursor: pointer;
  }
}
.Online {
  height: calc(94vh - 50px);
  width: 100%;
  position: relative;
}

#placeholder {
  width: 100%;
  height: calc(94vh - 50px);
}

.naviga-ai {
  // background-image: url('../../../assets/images/home/HomePage.png');
  // background-size: cover;

  // background-image: linear-gradient(to right, #8773f0 0%, #d5dcff 100%);
  height: 100%;
  // overflow-y: auto;

  .headerBox {
    display: flex;
    justify-content: space-between;
    align-items: center;
    box-sizing: border-box;
    width: 100%;
    height: 45px;
    line-height: 45px;
    .layout {
      border-top-left-radius: 10px;
      border-top-right-radius: 10px;
      // width: calc(100% - 60.5px);
      width: 100%;
      margin-bottom: 2px;
      border-bottom: 1px solid #eee;
      // border-top: 1px solid #eee;
      display: flex;
      justify-content: space-between;
      align-items: center;
      box-sizing: border-box;
      background-color: #fff;
    }

    .headerBox_file {
      height: 45px;
      display: flex;
      align-items: center;

      .btnmore {
        padding: 0 10px;
      }

      .file_box {
        width: 45px;
        height: 45px;
        display: flex;
        justify-content: space-around;
        align-items: center;

        .fileicon {
          font-size: 36px;
        }
      }
    }

    .headerBox_btn {
      display: flex;
      align-items: center;

      .btn_more {
        padding: 0 10px;
      }
    }
  }
}

/******************************************  导图样式start */

.chatMap {
  margin: 0 auto;
  width: 100%;
  background: #fff;
  border-radius: 8px;
}

.mermaid_box {
  width: 100%;
  background: #fff;
  border-radius: 8px;
  height: 100%;
}

.mermaids {
  margin: 0 auto;
  width: 100%;
  background: #fff;
  border-radius: 8px;
}
/******************************************  导图样式end*/

/******************************************  录音样式start */
.voice_box {
  height: 20px;
  cursor: pointer;

  .SpeakType3 {
    width: 60px;
    font-size: 12px;
    color: #b3b0c3;
  }
}
.loaderRectangle {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 0 3px;
}

.loaderRectangle div {
  width: 4px;
  height: 8px;
  animation: 0.9s ease-in-out infinite;
  background: #3662ec;
  box-shadow: 0 0 20px rgba(18, 31, 53, 0.3);
}

.loaderRectangle div:nth-child(1) {
  animation-name: rectangleOneAnim;
  animation-delay: 1s;
}

@keyframes rectangleOneAnim {
  0% {
    height: 8px;
  }

  40% {
    height: 15px;
  }

  100% {
    height: 8px;
  }
}

.loaderRectangle div:nth-child(2) {
  animation-name: rectangleTwoAnim;
  animation-delay: 1.1s;
}

@keyframes rectangleTwoAnim {
  0% {
    height: 8px;
  }

  40% {
    height: 20px;
  }

  100% {
    height: 8px;
  }
}

.loaderRectangle div:nth-child(3) {
  animation-name: rectangleThreeAnim;
  animation-delay: 1.2s;
}

@keyframes rectangleThreeAnim {
  0% {
    height: 8px;
  }

  40% {
    height: 25px;
  }

  100% {
    height: 8px;
  }
}

.loaderRectangle div:nth-child(4) {
  animation-name: rectangleFourAnim;
  animation-delay: 1.3s;
}

@keyframes rectangleFourAnim {
  0% {
    height: 8px;
  }

  40% {
    height: 20px;
  }

  100% {
    height: 8px;
  }
}

.loaderRectangle div:nth-child(5) {
  animation-name: rectangleFiveAnim;
  animation-delay: 1.4s;
}

@keyframes rectangleFiveAnim {
  0% {
    height: 8px;
  }

  40% {
    height: 15px;
  }

  100% {
    height: 8px;
  }
}

/******************************************  录音样式end */
.preview {
  padding: 15px 15px 0;
  width: 100%;
  // height: calc(100vh - 95px);
  height: calc(95vh - 15px);
  background-color: #f0f1f5;

  text-align: center;
  overflow: scroll;
  overflow-x: hidden;
  overflow-y: hidden;

  border-bottom-left-radius: 10px;
  // background-color: antiquewhite;

  .loading-overlay {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(255, 255, 255, 0.8);
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 1.5rem;
    color: #000;
    z-index: 1;
  }

  // border: 1px solid red;

  .iframeClass {
    width: 100%;
    box-shadow:
      0 6px 12px rgba(0, 0, 0, 0.3),
      0 4px 8px rgba(0, 0, 0, 0.2);
    height: calc(94vh - 30px);
  }
}

.box {
  width: 100%;
  display: flex;
  justify-content: space-between; //样式有问题就注释这个

  .reserve {
    width: 300px;
  }
  .page_left {
    // margin-right: 10px;

    // border: 1px solid red;
    // background-color: #f7f8fc;
    display: flex;

    .left_box {
      display: flex;
      flex-direction: column;
      align-items: center;
      padding: 5px;
      width: 65px;
      height: 100%;
      //   background: #f3f2ff;

      .talk-active {
        background: #a18ff4;
        border-radius: 50%;
      }
      .txt-active {
        color: #fff;
      }

      .talk_img {
        padding: 5px;
        width: 50px;
        height: 50px;
        margin-bottom: 10px;
        .img {
          width: 45px;
          height: 45px;
        }
      }

      .talk {
        padding: 5px;
        width: 50px;
        height: 80px;
        display: flex;
        flex-direction: column;
        justify-content: space-around;
        align-items: center;
        margin-bottom: 20px;
        cursor: pointer;
        border-radius: 8px;
        color: #dbdbdb;

        .talk_icon {
          width: 45px;
          height: 45px;
          display: flex;
          justify-content: center;
          align-items: center;
          flex-direction: column;
        }

        .icon_talk {
          margin-bottom: 3px;
          font-size: 25px;
        }
      }
    }

    .right_box {
      border-top-left-radius: 10px;
      border-bottom-left-radius: 10px;
      background: #ffffff;
      border-right: 1px solid #edeff573;
      //  border-radius: 10px;
      // background: #ffffff;
      width: calc(300px - 65px);
      // border: 1px solid brown;
      display: flex;
      flex-direction: column;
      height: 100%; /* 使容器占满父级高度 */
      padding: 10px;
      box-sizing: border-box;
    }

    .new_chat {
      margin-bottom: 10px;
      cursor: pointer;
      background: #554dd6;
      align-items: center;
      border-radius: 32px;
      display: flex;
      flex-shrink: 0; /* 防止头部在高度不足时被压缩 */
      font-size: 14px;
      font-weight: 400;
      height: 36px;
      justify-content: center;
      line-height: 24px;
      opacity: 1;
      transition: all 0.3s;
      color: #ffffff;

      .txt {
        margin-left: 6px;
      }
    }

    .activeSelected {
      background: #f3f2ff; /* 选中时的背景色 */
      color: #615ced; /* 选中时的字体颜色 */
    }

    .history_container {
      overflow-y: auto;
      flex-grow: 1; /* 使历史记录部分填充剩余空间 */
      //padding-right: 10px; /* 防止滚动条遮挡内容 */
      .history_chat {
        // color: #615ced;
        // background: #f3f2ff;
        align-items: center;
        border-radius: 12px;
        box-sizing: border-box;
        cursor: pointer;
        display: flex;
        flex-shrink: 0;
        font-size: 14px;
        height: 36px;
        justify-content: space-between;
        margin-bottom: 12px;
        outline: none;
        padding: 6px 16px;
        position: relative;
        transition: 0.2s ease;

        &:hover {
          color: #615ced;
          background: #f3f2ff;
          .icons_file {
            display: block;
          }
        }
      }

      .icons {
        display: flex;
      }

      .icons_file {
        display: none;
        font-size: 14px;
      }

      .icons_del {
        font-size: 14px;
      }
    }

    // .history_chat :hover .icons_file {
    //   display: block;
    // }

    /* 用于支持滚动的部分 */
    .right_box {
      display: flex;
      flex-direction: column;
      height: 100%;
    }

    .clear_history {
      color: #fff;
      display: flex;
      align-items: center;
      justify-content: center;
      margin-top: auto; /* 确保尾部固定在底部 */
      cursor: pointer;
      background: #554dd6;
      border-radius: 32px;
      padding: 6px 16px;
      font-size: 14px;
      font-weight: 400;
      height: 36px;
      line-height: 24px;
      opacity: 1;
      transition: all 0.3s;
      flex-shrink: 0; /* 防止尾部被压缩 */
      margin-top: 10px;

      .icon_clear {
        font-size: 15px;
      }

      .clear_txt {
        font-size: 15px;
        margin-left: 6px;
        letter-spacing: 1px;
        font-family: inherit;
      }
    }
  }
}
/* 聊天消息样式 */
.ai-message .message-content-wrapper {
  display: flex;
  // align-items: center;
}

.ai-message .AIavatar {
  width: 30px;
  height: 30px;
  margin-right: 10px;
}

/* 用户消息样式 */
.user-message .message-content {
  background-color: #f1f1f1;
  color: #333;
}

.ai-message .message-content {
  // background-color: #e1e1e147;
  color: #00796b;
}

.stop_box {
  display: flex;
  align-items: center;
  margin-top: 5px;

  .stop_icon {
    margin-left: 5px;
    cursor: pointer;
  }
}

/* loading 状态的样式 */
.ai-message .message-content-wrapper .message-content {
  color: #999;
  //font-style: italic;
}

.loading-text {
  color: #888;
  //font-style: italic;
  animation: loading 1s infinite;
}

@keyframes loading {
  0% {
    opacity: 0.5;
  }
  50% {
    opacity: 1;
  }
  100% {
    opacity: 0.5;
  }
}

.textFile {
  background: #fff;
}

.page_File {
  width: 900px;
  margin: 0 auto;
  //   margin-right: 280px;
  //background: #fff;  //注释
  overflow-x: auto;
  padding: 10px;
  // height: 0; /* 默认高度为 0 */
  //   max-height: calc(100vh - 280px); /* 最大高度 */
  max-height: calc(100vh - 190px); /* 最大高度 */
  // max-height: calc(100vh - 365px); /* 最大高度 */
  transition: height 0.5s ease-in-out; /* 过渡效果 */
  //box-shadow: 0 0 5px rgba(0, 0, 0, 0.1); //注释
  margin-bottom: 10px;
  border-radius: 8px;

  /* 聊天容器 */
  .chat-container {
    // border: 1px solid red;
    display: flex;
    flex-direction: column;
    height: calc(94vh - 240px);
    /* 占用视口高度，减去头部/底部的空间 */
    //background-color: #fff; //注释
  }

  /* 聊天消息区域 */
  .chat-messages {
    flex: 1;
    overflow-y: auto;
    /* 超过内容时滚动 */
    // margin-bottom: 10px;
    //background-color: #fff;//注释

    // box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
    // padding: 10px;
    display: flex;
    flex-direction: column;
  }

  /* 用户消息的样式（右对齐） */
  .user-message {
    flex-direction: row-reverse;
    /* 用户消息右对齐 */
    justify-content: flex-end;
  }

  /* AI（或其他人的）消息样式（左对齐） */
  .ai-message {
    flex-direction: row;
    /* AI消息左对齐 */
    justify-content: flex-start;
  }

  .messageisUser {
    display: flex;
    // align-items: flex-start;
    align-items: center;
    justify-content: flex-end;
    margin-bottom: 10px;
    //max-width: 75%; /* 限制最大宽度 */
    // padding: 5px;
  }

  /* 消息内容样式 */
  .message-content {
    padding: 10px;
    border-radius: 10px;
    word-wrap: break-word;
    line-height: 1.4;
    max-width: 90%;
    // background-color: #fff;
    /* 消息内容最大宽度 */
  }

  /* 用户的消息样式 */
  .message-content.user {
    background-color: #0084ff;
    color: white;
    align-self: flex-end;
    /* 用户消息靠右对齐 */
  }

  /* 其他用户或AI的消息样式 */
  .message-content.other {
    background-color: #e1e1e1;
    color: black;
    align-self: flex-start;
    /* AI消息靠左对齐 */
  }

  .others {
    padding: 6px;
    background: #fff;
    border-radius: 10px;
  }

  .avatarUser {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-size: 12px;
    background-color: #56abfb;
    margin-left: 8px;
    /* 为了给消息内容腾出空间 */
  }

  /* 每条消息 */
  .message-content-wrapper {
    display: flex;
    // align-items: flex-start;
    // align-items: center;
    margin-bottom: 10px;
    //max-width: 75%; /* 限制最大宽度 */
    // padding: 5px;
  }

  .AIavatar {
    margin-top: 21px;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-right: 8px;
    /* 为了给消息内容腾出空间 */
    border: 1px solid #56abfb;
    // background-color: #56abfb;
  }
  .summaryAvatar {
    // margin-top: 21px;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-right: 8px;
    /* 为了给消息内容腾出空间 */
    border: 1px solid #56abfb;
  }
}

/* 为了视觉效果可以在进入时加个渐变 */
.page_File-enter-active,
.page_File-leave-active {
  transition: height 0.5s ease-in-out;
}

.page_File-enter,
.page_File-leave-to {
  height: 0; /* 初始/结束高度 */
}

.icon_file {
  height: 100%;
  font-size: 49px;
  /* vertical-align: middle; */
  /* margin-right: 6px; */
  margin-left: -7px;
}

.file-list {
  //   margin-right: 280px;
  width: 100%;
  margin: 0 auto;
  // max-height: 260px;
  padding-bottom: 12px;
  border-radius: 6px;
  // background-color: #f3f5f9;
  overflow-y: auto;
  padding: 10px;

  .file-item {
    padding: 8px;
    width: calc((100% - 16px) / 3);
    position: relative;
    height: 60px;
    background: #fff;
    border-color: #fff;
    border-radius: 8px;
    box-shadow: 0px 0px 15px rgba(0, 0, 0, 0.3);
  }

  .file-box {
    display: flex;

    .file-name {
      margin-left: 10px;
      display: flex;
      flex-direction: column;

      .file_name {
        margin: 0px;
        font-family: 'PingFang SC', 'Microsoft YaHei', SimHei;
        font-weight: 700;
        font-size: 14px;
        line-height: 20px;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }

      .file-size {
        margin: 0px;
        font-size: 13px;
        line-height: 24px;
        font-weight: 400;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }
    }
  }

  .file-icon {
    width: 35px;
    height: 45px;
  }

  .fork-icon {
    position: absolute;
    cursor: pointer;
    font-size: 14px;
    top: -6px;
    right: -2px;
  }
}

.fileup {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-around;
  width: calc(100vw - 0px);
  // height: calc(100vh - 20px);
  background-color: #fff;
  // border-bottom-right-radius: 10px;
  // border-radius: 10px;

  &.full-radius {
    border-radius: 0;
  }

  &.bottom-right-radius {
    border-bottom-right-radius: 10px;
  }

  .info {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: space-around;

    .title {
      font-size: 35px;
      color: #615ced;
      font-weight: bold;
    }

    .desc {
      color: #8f91a8;
      font-size: 15px;
      // height: 12px;
      // line-height: 12px;
      letter-spacing: 1px;
      overflow: hidden;
      text-align: center;
      text-overflow: ellipsis;
      white-space: nowrap;

      flex-shrink: 0;
      margin: 15px 0;
    }

    .start {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      width: 150px;
      height: 45px;
      border-radius: 10px;
      cursor: pointer;
      background: #615ced;
      color: #fff;
      margin-top: 15px;
    }
  }

  .file {
    width: 650px;
    height: 320px;
    // background: #8f74f30d;
    // 如果想要渐变更加平滑，可以调整颜色停止点
    background-image: linear-gradient(to bottom, #d4dbff69 0%, #d4dbff33 50%, #ffffff 100%);

    border-radius: 10px;
    border: 2px dashed #aaa1f7;

    .icon {
      display: flex;
      margin-bottom: 15px;

      .svgicon {
        width: 100%;
        height: 100%;
      }
      .icons_box {
        width: 43px;
        height: 45px;
      }

      .icons_boxs {
        width: 43px;
        height: 45px;
        margin: 0 10px;
      }
    }

    .file-upload {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      height: calc(320px - 80px);

      .txt {
        color: #54555c;
        font-size: 25px;
        font-weight: bold;
      }

      .desc-file {
        font-size: 15px;
        color: #808085;
        letter-spacing: 1px;
        overflow: hidden;
        text-align: center;
        text-overflow: ellipsis;
        white-space: nowrap;

        flex-shrink: 0;
        margin: 15px 0;
      }

      .upload-btn {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        width: 150px;
        height: 45px;
        border: 2px solid #615ced;
        border-radius: 10px;
        cursor: pointer;
        color: #615ced;
      }
    }
  }
}

.input-bot {
  // border-top-right-radius: 10px;
  border-bottom-right-radius: 10px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between; //022
  // width: calc(100vw - 300px);
  //   width: 800px;
  height: calc(95vh - 38px);
  // background: #cccccc4a;

  .input_tab {
    margin: 0 auto;
    // width: 900px;
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: 50px;
    padding: 8px;
    // border-radius: 16px;
    // background: rgba(255, 255, 255, 0.4);
    background: #fff;
    // margin-bottom: 8px;

    .talk-tab {
      display: flex;
      height: 100%;
      align-items: center;
      justify-content: center;
      padding: 0 10px;
      font-size: 16px;
      // border-radius: 10px;
      cursor: pointer;
      letter-spacing: 1.5px;

      .size_icon {
        font-size: 16px;
        font-weight: 600;
        margin-right: 6px;
      }
    }

    .talktab {
      display: flex;
      height: 100%;
      align-items: center;
      justify-content: center;
      font-size: 16px;
      // border-radius: 10px;
      cursor: pointer;
      letter-spacing: 1.5px;
    }
  }

  .activeIcon {
    color: #615ced;
  }

  .activeTab {
    border-radius: 10px;
    font-weight: 600;
    color: #615ced;
    background: #f3f2ff;
    box-shadow: 0 4px 16px 1px #0000000f;
    // font-weight: 600;
    // color: #615ced;
    // border-bottom: 2px solid #615ced; /* 底部添加线条 */
    // background: none; /* 移除背景色 */
    // box-shadow: none; /* 移除阴影 */
  }

  .svgact {
    font-weight: 600;
    color: #615ced;
  }

  .tips {
    color: #8f91a8;
    font-size: 10px;
    height: 12px;
    line-height: 12px;
    margin: 0;
    overflow: hidden;
    text-align: center;
    text-overflow: ellipsis;
    white-space: nowrap;
    width: 100%;
    flex-shrink: 0;
    margin: 8px 0;
  }
}

.page_input {
  width: 100%;
  width: 900px;
  margin: 0 auto;
  // max-width: 760px;
  // max-height: 150px;
  overflow-y: auto;
  //   margin: 0 auto;
  //   margin-right: 280px;
  display: flex;
  justify-content: center;
  align-items: flex-end;

  .create_btn {
    margin-left: 8px;
    // margin-bottom: 8px;
  }

  .img2 {
    width: 16px;
    height: 16px;
  }

  .input_box {
    border: 1px solid #d5dbff;
    flex: 1;
    display: flex;
    align-items: flex-end;
    background-color: #ffffff;
    border-radius: 6px;
    // border: 1px solid #ffdeae;
    box-shadow: 0px 0px 8px 0px rgba(240, 143, 0, 0.06);
    overflow-y: auto;
    padding: 8px;
    margin: 0 auto;

    :deep(.el-textarea__inner) {
      box-shadow: none;
    }

    .btn_box {
      display: flex;
      align-items: center;
      margin-bottom: 5px;
    }
  }

  .voice_file {
    height: 20px;
  }

  .sendBtn {
    width: 28px;
    height: 28px;
    text-align: center;
    line-height: 28px;
    background-color: #554dd6;
    color: #ffffff;
    border-radius: 6px;
    // margin-left: 8px;
    font-size: 17px;
    cursor: pointer;
  }
}

.input_box_input {
  padding: 8px 10px;
  width: 100%;
  height: 100%;
  max-height: 73px;
  display: flex;
  border-radius: 10px;
  align-items: flex-end;
  background: #ffffff;
}

textarea::-webkit-scrollbar {
  width: 3px;
  /* 设置滚动条宽度 */
}

textarea::-webkit-scrollbar-thumb {
  background-color: rgb(66, 70, 86);
  /* 设置滚动条滑块的背景色 */
  border-radius: 50%;
  /* 设置滑块的圆角 */
}

.textarea {
  &:focus {
    outline: none;
  }
}

:deep(.textInput1) {
  width: 100%;
  height: 33px;

  &:deep(.el-textarea__inner) {
    border: 0;
    font-size: 15px;
  }
}

:deep(.el-textarea__inner) {
  box-shadow: none !important;
  border: 0;
}

.send_btn_box {
  display: flex;
  align-items: center;

  img {
    cursor: pointer;
  }
}

// .voice_box {
//   cursor: pointer;

//   .SpeakType3 {
//     width: 60px;
//     font-size: 12px;
//     color: #b3b0c3;
//   }
// }

.send_btn {
  width: 67px;
  padding: 8px 0;
  text-align: center;
  border-radius: 8px;
  background-color: #5e7afc;
  color: #ffffff;
  margin-left: 16px;
  cursor: pointer;
}

.search-active {
  font-weight: 600;
  color: #202020;
  background: #ffffff;
  box-shadow: 0 4px 16px 1px #0000000f;
}

.icon_size {
  font-weight: 600;
  margin-right: 6px;
}

.top {
  width: 260px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 58px;
  padding: 8px;
  margin-bottom: 20px;
  border-radius: 16px;
  background: rgba(255, 255, 255, 0.4);

  .top-text {
    display: flex;
    height: 100%;
    align-items: center;
    justify-content: center;
    padding: 0 18px;
    font-size: 15px;
    border-radius: 10px;
    cursor: pointer;
    letter-spacing: 1.5px;
  }
}

.search_box {
  width: 100%;
}

:deep(.input_search) {
  border: none;
  width: 100%;
}

:deep(.el-input__wrapper) {
  border: none;
  padding: 0px;
  box-shadow: none;
  border-radius: 10px;
}

:deep(.el-input__inner:hover),
:deep(.el-input__inner:focus) {
  border: 2px solid #4a9dec;
  box-shadow: 0px 0px 0px 7px rgb(74, 157, 236, 20%);
  background-color: white;
}

:deep(.el-input__prefix) {
  top: 2px;
}

:deep(.el-input-group__prepend) {
  border-top-left-radius: 20px;
  border-bottom-left-radius: 20px;
  background-color: #3d9cfb;
  border-color: #3d9cfb;
  color: #ffffff;
}

:deep(.el-input__inner) {
  // padding-top: 8px;
  // padding-bottom: 8px;
  // line-height: 40px;
  // height: 40px;
  // // border-radius: 16px;
  // border-top-right-radius: 20px;
  // border-bottom-right-radius: 20px;
  border: 2px solid transparent;
  outline: none;
  overflow: hidden;
  background-color: #ffffff;
  border-radius: 10px;
  transition: all 0.5s;
  // border: 2px solid #4a9dec;
  box-shadow: 0 0.4rem #dfd9d9;
  padding-left: 8px;
}

.searchInput_name {
  width: 100%;
  display: flex;
  align-items: center;

  div {
    // width: 10px;
    overflow: hidden;
    /*内容超出后隐藏*/
    text-overflow: ellipsis;
    /*超出内容显示为省略号*/
    white-space: nowrap;
    /*文本不进行换行*/
  }
}

.content_box {
  border-bottom: 1px solid #efefef;
}

.search_docContent {
  font-size: 12px;
  color: #939292;
  line-height: 22px;
}

.superiorsPath {
  font-size: 12px;
  color: #d6d6d6;
  line-height: 22px;
  text-align: right;
  overflow: hidden;
  /*内容超出后隐藏*/
  text-overflow: ellipsis;
  /*超出内容显示为省略号*/
  white-space: nowrap;
  /*文本不进行换行*/
}

.folder {
  position: relative;
  animation: float 1.8s infinite ease-in-out;
  transition: transform 0.3s ease;
  margin-bottom: 6px;
}

.folder:hover {
  transform: scale(1.05);
}

.folder .top {
  background: linear-gradient(135deg, #ff9a56, #ff6f56);
  width: 60px;
  height: 15px;
  border-radius: 12px 12px 0 0;
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
  position: relative;
  z-index: 2;
}

.folder .bottom {
  background: linear-gradient(135deg, #ffe563, #ffc663);
  width: 100px;
  height: 70px;
  box-shadow: 0 15px 30px rgba(0, 0, 0, 0.3);
  border-radius: 0 10px 10px 10px;
  position: relative;
  top: -10px;
}

@keyframes float {
  0% {
    transform: translateY(0px);
  }

  50% {
    transform: translateY(-12px);
  }

  100% {
    transform: translateY(0px);
  }
}

.page_tags {
  margin-top: 15px;

  .tagclass {
    margin-right: 10px;
    cursor: pointer;
  }
}
</style>
